如何动态地将mat-error添加到mat-input-field?

问题描述 投票:0回答:2

我希望在用户超过maxLength时通过动态向DOM添加<mat-error>来显示错误。

我已经有一个属性指令来限制输入字段的最大长度。我将它作为一个指令,因为它应用于项目中不同文件的许多输入字段。但现在问题是,当用户超出限制时,我必须显示mat-error。我不希望自己在所有文件的每个输入字段下添加<mat-error>,我想要一个模块化的解决方案。可以通过使用现有指令本身来完成吗?

<mat-form-field floatLabel="auto">
      <input [formControl]="displayNameControl"
        mongoIndexLimit
        [charLength]="charLength"
        matInput
        name="displayName"
        placeholder="Stack Name"
        autocomplete="off"
        required />
    </mat-form-field>

这是我的指示

import { Directive, OnInit, NgModule, ElementRef, OnChanges, Input, SimpleChanges, Renderer2 } from '@angular/core';

@Directive({
  selector: '[mongoIndexLimit]'
})
export class MongoIndexLimitDirective implements OnInit, OnChanges {
  @Input() public charLength?: number;
  private maxLength = 5;
  constructor(
    private el: ElementRef<HTMLElement>,
    private renderer: Renderer2
  ) { }

  public ngOnInit() {
    this.el.nativeElement.setAttribute('maxLength', this.maxLength.toString());
  }

  public ngOnChanges(changes: SimpleChanges) {
    if (changes.charLength.currentValue >= 5) {
      const child = document.createElement('mat-error');
      this.renderer.appendChild(this.el.nativeElement.parentElement.parentElement.parentElement, child);
    }
  }

}

当我尝试上面的时候我能够将一个<mat-error>元素附加到DOM,但angular不会将它视为编译器<mat-error>角度材质。它只是一个虚拟的<mat-error>,而不是一个材料组件。

我希望结果是一个带有maxLength设置的输入组件和一个动态生成的mat-error,它显示限制何时超出,就像下面的例子中的方式一样。

https://material.angular.io/components/input/examples(标题为自定义错误状态匹配器的输入)

对不起,我的英语不好 。

angular typescript angular-material
2个回答
2
投票

当然,您可以动态添加mat-error。关于这一点,NetBasal中有一个qazxsw poi。

我制作的一个简单的版本是在amazing article。在这个stackblitz中,我将指令附加到mat-form-field并进行解决,以附加新的组件mat-error-component。这允许我使用CSS和动画。

关键是使用ViewContainerRef使用ComponentFactoryResolver动态添加组件

嗯,指令的代码:

stackblitz

MatErrorComponent(为了方便起见,我把它称为它。可能需要放入主模块的entryComponents)看起来比实际更复杂因为“动画”,但实际上是一个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; }

<mat-error>{{message}}</mat-error>

更新了mat-error-component的更好方法。

我们可以考虑不同的错误并改善转换

@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'
    }
  }

这允许当消息错误改变时,发生新的动画 - 在这种情况下,如果例如将不透明度从0改变为1。在我们的指令中将函数onChange更改为

@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;
  }
} 

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('') }


0
投票

你没有动态添加qazxsw poi,你只需把它放在那里。它与qazxsw poi严格合作,如果improve stackblitz将在mat-error州,它将变得可见。

威胁它作为错误消息的容器。您所要做的就是调整消息(如果您可以拥有多个验证规则并希望所有这些规则都有自定义消息)。

来自Angular Material docs的代码

mat-form-field
© www.soinside.com 2019 - 2024. All rights reserved.