Динамически создатькомпонент и должен быть спроецирован в родительскийкомпонент правильно - PullRequest
3 голосов
/ 22 октября 2019

Использование ComponentFactoryResolver для динамического создания компонента является прямым, но, похоже, он не проецирует созданный компонент в родительский, когда я пытаюсь сделать это для компонента Angular Material <mat-error> внутри <mat-form-field>,Я использовал пример от Netanel Basal с компонентами Bootstrap, который отлично подходит для генерации ошибок управления формой, но из-за проекции содержимого, используемой в Angular Material с <mat-error>, я не могу его получитьработа для Angular Material v8.2.1.

Возможно ли динамически создать <mat-error> в <mat-form-field> и правильно ли он проектировать контент?

Ответы [ 2 ]

1 голос
/ 26 октября 2019

Я пробовал это раньше - MatFormField получает MatError s через ContentChildren. Поскольку это проекция контента, динамическое добавление или удаление таких элементов, как MatError, не работает - шаблон контента компилируется и обрабатывается иначе, чем другие шаблоны.

Вы упомянули в комментарии, который пытаетесь обработатьсогласованный обмен сообщениями об ошибках по шаблонам ... почему бы не добавить directive к элементу <mat-error>, который управляет обменом сообщениями об ошибках на основе состояния проверки формы родительского элемента управления?

Если вы 'Тем не менее, вы хотите управлять шаблонами, но вы не можете использовать директиву. Однако вы можете создать компонент и использовать как директиву:

@Component({
  selector: '[matErrorMessages]',
  template: '{{ error }}'
})
export class MatErrorMessagesDirective implements AfterViewInit {

  public error = '';
  private inputRef: MatFormFieldControl<MatInput>;

  constructor(private _inj: Injector) { }

  public ngAfterViewInit() {
    // grab reference to MatFormField directive, where form control is accessible.
    let container = this._inj.get(MatFormField);
    this.inputRef = container._control;

    // sub to the control's status stream
    this.inputRef.ngControl.statusChanges.subscribe(this.updateErrors);
  }


  private updateErrors = (state: 'VALID' | 'INVALID') => {
    if (state === 'INVALID') {
      // active errors on the FormControl
      let controlErrors = this.inputRef.ngControl.errors;

      // just grab one error
      const firstError = Object.keys(controlErrors)[0];

      if(firstError === 'required')
        this.error = 'This field is required.';

      if(firstError === 'minlength')
        this.error = 'This field should be longer.';

      if(firstError === 'error from my own custom validator')
        this.error = 'You get the point.';
      // ..... 
    }
  }

затем в шаблоне ....

<mat-error matErrorMessages></mat-error>

Таким образом, выпусть MatFormField контролирует наличие MatError, как это должно быть, но вы контролируете content элемента error локальным, чистым способом.

stackblitzвыше: https://stackblitz.com/edit/angular-sjkfft

Вы должны покопаться в закрытых членах компонентов Material, что является сомнительной практикой и может порвать с обновлениями библиотеки, но это работает.

У меня действительно есть репозиторий для этого типа сообщений об ошибках, который был написан для гораздо более старой версии @ angular / material, но я также смог взять в руки сам Validator для лучшего обмена сообщениями об ошибках. и вводил в модуль целый список пользовательских валидаторов / ошибок для этого валидатора: https://github.com/joh04667/material-error-messages

0 голосов
/ 31 октября 2019

это просто еще одно альтернативное решение, вдохновленное ngx-valdemort для создания компонента для сообщения об ошибке проверки дескриптора элемента управления, просто необходимо быть дочерним в теле formGroup ипередайте имя элемента управления формы, и оно не ограничено угловым компонентом материала.

@Component({
  selector: 'error-summary',
  templateUrl: './error-summary.component.html',
  styleUrls: ['./error-summary.component.css']
})
export class ErrorSummaryComponent  {

  @Input() control:string;

  @Input() visible:any;

  constructor(private controlContainer: ControlContainer) { }

  get form():FormGroup {
    return this.controlContainer.control  as FormGroup;
  }

  get formControl() :AbstractControl{
    return this.form.get(this.control) as AbstractControl;
  }

  get isNotValid() {
    return this.formControl.invalid && (this.formControl.touched || this.formControl.dirty)
  }

}

template

<ng-container *ngIf="isNotValid"  >
  <ng-container *ngIf="formControl.hasError('required')"> this is required </ng-container>
  <ng-container *ngIf="formControl.hasError('email')">this not valid email format</ng-container>
  <ng-container *ngIf="formControl.hasError('maxlength')">max ...</ng-container>
  <ng-container *ngIf="formControl.hasError('minlength')">min ...</ng-container>
</ng-container>

и может использоваться следующим образом

<form [formGroup]="form">

  <mat-form-field>
        <input matInput placeholder="Enter your email" formControlName="email">
  </mat-form-field>
    <error-summary control="email" ></error-summary>

  ...

</form>

демо ??

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...