Angular6 - Получение проблем и неправильное поведение при попытке реализовать вложенное пользовательское поле формы внутри моей формы (используя Angular Material) - PullRequest
0 голосов
/ 15 мая 2019

Я использую угловой материал для создания формы, где я зацикливаюсь с директивой * ngFor для отображения множества входных данных различных типов. Что я хочу сделать, так это вставить matInput в другой компонент и повторно использовать его внутри моей формы. Я думаю, что я близок к тому, чтобы сделать это, но я застрял более чем на 3 дня с этой ошибкой консоли:

formControlName должно использоваться с родительской директивой formGroup. Вы будете хотите добавить директиву formGroup и передать ей существующую FormGroup экземпляр (вы можете создать его в своем классе).

Пример:

<div [formGroup]="myGroup">
  <input formControlName="firstName">
</div>

In your class:

this.myGroup = new FormGroup({
   firstName: new FormControl()
});

Эта ошибка не имеет смысла для меня, потому что у меня уже есть директива [formGroup], реализованная в моей форме, как вы увидите ниже. Поэтому мне интересно, как я могу решить эту ошибку.

По сути, я до сих пор следовал руководству на официальном сайте материала: https://material.angular.io/guide/creating-a-custom-form-field-control#trying-it-out Вот некоторый код, чтобы показать вам, что я реализовывал:

input.component.html

<input matInput
  placeholder="placeholder"
  formControlName="formControlName"
/>

input.component.ts

import { Component, Input, HostBinding, Self, Optional, ElementRef, Output } from '@angular/core';
import { MatFormFieldControl } from '@angular/material';
import { FormControlName, ControlValueAccessor, NgControl, FormBuilder, FormGroup } from '@angular/forms';
import { Subject } from 'rxjs';
import { FocusMonitor } from '@angular/cdk/a11y';
import { coerceBooleanProperty } from '@angular/cdk/coercion';


class MyInput {
  constructor(public ftdName: string, public ftdConformite: string, public ftdEmetteur: string,
              public ftdNation: string, public ftdNonConformite: string, public ftdGed: string, 
              public ftdConstatExterne: string) { }
}

@Component({
  selector: 'app-input',
  templateUrl: './input.component.html',
  styleUrls: ['./input.component.css'],
  providers: [
    {
      provide : MatFormFieldControl, useExisting: InputComponent
    }]
})

export class InputComponent implements ControlValueAccessor, MatFormFieldControl<MyInput> {

  static nextId = 0;
  public _placeholder: string;
  public _disabled = false;
  public _required = false;
  public stateChanges = new Subject<void> ();
  public focused = false;
  public errorState = false;
  public listForm: FormGroup;

  onChange: any = () => {}
  onTouch: any = () => {}

  @HostBinding('class.floating')
  get shouldLabelFloat() {
    return this.focused || !this.empty;
  }

  get empty() {
    let n = this.listForm.value;
    return !n.ftdName && !n.ftdConformite && !n.ftdNonConformite && !n.ftdConstatExterne && !n.ftdEmetteur && !n.ftdGed && !n.ftdNation;
  } 

  @HostBinding('attr.aria-describedby') describedBy = '';
  setDescribedByIds(ids: string[]) {
    this.describedBy = ids.join(' ');
  }

  @HostBinding() id = `example-myinput-${InputComponent.nextId++}`

  @Input() 
  formControlName: FormControlName;

  @Input() 
  get placeholder() {
    return this._placeholder
  }
  set placeholder(plh) {
    this._placeholder = plh;
    this.stateChanges.next();
  }

  @Input()
  get required() {
    return this._required;
  }
  set required(req) {
    this._required = coerceBooleanProperty(req);
    this.stateChanges.next();
  }

  @Input()
  get disabled(): boolean {
     return this._disabled;
  }
  set disabled(value: boolean) {
    this._disabled = coerceBooleanProperty(value);
    this._disabled ? this.listForm.disable() : this.listForm.enable();
    this.stateChanges.next();
  }

  constructor(@Optional() @Self() public ngControl : NgControl,
  fb: FormBuilder, private fm: FocusMonitor, private elRef: ElementRef<HTMLElement>) { 

    this.listForm = fb.group({
      'ftdName' : '',
      'ftdConformite' : '',
      'ftdEmetteur' : '',
      'ftdNation' : '',
      'ftdNonConformite' : '',
      'ftdGed' : '', 
      'ftdConstatExterne' : ''
    })

    fm.monitor(elRef.nativeElement, true)
    .subscribe(origin => {
      this.focused = !!origin;
      this.stateChanges.next();
    });

    if(this.ngControl != null) {
      this.ngControl.valueAccessor = this
    }
  }

  onContainerClick(event: MouseEvent) {
    if ((event.target as Element).tagName.toLowerCase() != 'input') {
      this.elRef.nativeElement.querySelector('input').focus();
    }
  }

  set value(input : MyInput | null) {
    this.stateChanges.next();
  }

  // this method sets the value programmatically
  writeValue(value:any) {
    this.value = value
  }
  // upon UI element value changes, this method gets triggered
  registerOnChange(fn: any){
    this.onChange = fn
  }

  // upon touching the element, this method gets triggered
  registerOnTouched(fn: any){
    this.onTouch = fn
  }

  ngOnDestroy() {
    this.stateChanges.complete();
    this.fm.stopMonitoring(this.elRef.nativeElement);
  }
}

form.component.html (где я называю свой ввод данных приложения, я упрощаю код, чтобы показать только ту часть, которая касается моей проблемы.)

<div class="matContainer">
  <form class="EventForm" [formGroup]="listForm" (ngSubmit)="onSubmitList()">
    <ng-container *ngFor="let group of jsonArrays.groups; let last = last">
      <ng-container *ngFor="let input of group.inputs">

        <mat-form-field *ngIf="input.type === 'matInput'" class="colonne{{ 
         input.colonne }}">
          <app-input 
            placeholder="{{ input.placeholder }}"
            formControlName="{{ input.formControlName }}"
          ></app-input>
        </mat-form-field>

      </ng-container>
    </ng-container>
  </form>
</div>

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

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