Как динамически добавить mat-error в mat-input-field? - PullRequest
0 голосов
/ 01 мая 2019

Я хочу показать ошибку, когда пользователь превышает maxLength, динамически добавляя в DOM.

У меня уже есть директива атрибута для ограничения максимальной длины поля ввода. У меня есть это как директива, так как это применяется ко многим полям ввода в разных файлах проекта. Но теперь проблема в том, что я должен показать mat-error , когда пользователь превысит лимит. Я не хочу добавлять в каждое поле ввода для всех файлов самостоятельно, мне нужно решение modular . Можно ли это сделать с помощью самой существующей директивы?

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

}

Когда я попробовал описанное выше, я смог добавить элемент в DOM, но angular не воспринимает его как угловой материал компилятора . это просто фиктивная , а не материальная составляющая.

Я хочу, чтобы результатом был входной компонент с установленным параметром maxLength и динамически генерируемой ошибкой mat, которая показывает, когда предел превышает, точно так же, как в примере ниже.

https://material.angular.io/components/input/examples (озаглавленный «Ввод с пользовательским сопоставлением состояний ошибок»)

Извините за мой плохой английский.

Ответы [ 2 ]

2 голосов
/ 01 мая 2019

Конечно, вы можете динамически добавить ошибку в мат.В 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

0 голосов
/ 01 мая 2019

Вы не добавляете mat-error динамически, вы просто помещаете его туда. Он строго взаимодействует с mat-form-field и станет видимым, если matInput будет в состоянии invalid.

Угроза как контейнер для сообщения об ошибке. Все, что вам нужно сделать, это настроить сообщение (в случае, если у вас может быть несколько правил проверки и вам нужны настраиваемые сообщения для всех них).

Код из угловых материалов документов

<div class="example-container">
  <mat-form-field>
    <input matInput placeholder="Enter your email" [formControl]="email" required>
    <mat-error *ngIf="email.invalid">{{getErrorMessage()}}</mat-error>
  </mat-form-field>
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...