Конечно, вы можете динамически добавить ошибку в мат.В NetBasal есть удивительная статья об этом.
Простая версия, которую я делаю, находится в stackblitz .В этом стеке я добавляю директиву к полю mat-form и делаю обходной путь, чтобы присоединить новый компонент mat-error-component.Это позволяет мне использовать css и анимации.
Ключ заключается в использовании ViewContainerRef для динамического добавления компонента с использованием ComponentFactoryResolver
Ну, код директивы:
export class MongoIndexLimitDirective implements AfterViewInit {
ref: ComponentRef<MatErrorComponent>;
constructor(
private vcr: ViewContainerRef,
private resolver: ComponentFactoryResolver,
private formField:MatFormField
) { }
public ngAfterViewInit()
{
this.formField._control.ngControl.statusChanges.subscribe(res=>this.onChange(res))
}
public onChange(res) {
if (this.formField._control.ngControl.invalid)
{
this.setError('error')
}
else
this.setError('')
}
setError(text: string) {
if (!this.ref) {
const factory = this.resolver.resolveComponentFactory(MatErrorComponent);
this.formField._elementRef
this.ref = this.vcr.createComponent(factory);
}
this.ref.instance.error=text;
}
MatErrorComponent (для удобства я назвал его. Будьте осторожны, если вам нужно вставить элемент entryComponents основного модуля), он выглядит более сложным, чем реальным, потому что это "анимации", но по сути это <mat-error>{{message}}</mat-error>
@Component({
selector: 'custom-error',
template:`
<div [@animation]="_state" style="margin-top:-1rem;font-size:.75rem">
<mat-error >
{{message}}
</mat-error>
</div>
`,
animations: [
trigger('animation', [
state('show', style({
opacity: 1,
})),
state('hide', style({
opacity: 0,
transform: 'translateY(-1rem)'
})),
transition('show => hide', animate('200ms ease-out')),
transition('* => show', animate('200ms ease-in'))
]),
]
})
export class MatErrorComponent{
_error:any
_state:any
message;
@Input()
set error(value)
{
if (value && !this.message)
{
this.message=value;
this._state='hide'
setTimeout(()=>
{
this._state='show'
})
}
else{
this._error=value;
this._state=value?'show':'hide'
}
}
Обновлен улучшен подход к компоненту mat-error.
Мы можем учесть различия в ошибках и улучшить переход, например
@Component({
selector: '[custom-error]',
template: `
<div [@animation]="increment" *ngIf="show" style="margin-top:-1rem;font-size:.75rem">
<mat-error >
{{message}}
</mat-error>
</div>
`,
animations: [
trigger('animation', [
transition(':increment', [
style({ opacity: 0}),
animate('200ms ease-in', style({ opacity: 1 })),
]),
transition(':enter', [
style({ opacity: 0, transform: 'translateY(-1rem)' }),
animate('200ms ease-in', style({ opacity: 1, transform: 'translateY(0)' })),
]),
transition(':leave', [
animate('200ms ease-out', style({ opacity: 0, transform: 'translateY(-1rem)' }))
])])
]
})
export class MatErrorComponent {
show: boolean
message: string;
increment:number=0;
@Input()
set error(value) {
if (value)
{
if (this.message!=value)
this.increment++;
this.message = value;
}
this.show = value ? true : false;
}
}
Это позволяеткак и при изменении сообщения об ошибке, возникает новая анимация - в этом случае измените непрозрачность с 0 на 1, если, например, в нашей директиве измените функцию onChange на
public onChange(res) {
if (this.control.invalid)
{
if (this.control.errors.required)
this.setError(this.formField._control.placeholder+' required')
else
this.setError(this.formField._control.placeholder+' incorrect')
}
else
this.setError('')
}
См. улучшение stackblitz