Angular Не удается найти элемент управления с неуказанным атрибутом имени

Я знаю, что этот вопрос возникает несколько раз каждый год, но я не могу его запустить. Мне нужно динамически создавать formArray в зависимости от элементов, заданных массивом. Пробовал несколько попыток, и я застрял, чтобы попробовать среду: https://medium.com/aubergine-solutions/add-push-and-remove-form-fields-dynamically-to-formarray-with-reactive-forms-in-angular-acf61b4a2afe

Мой HTML:

<mat-accordion class="example-headers-align">
    <form [formGroup]="formGroup">
        <mat-expansion-panel [expanded]="step === item.step" (opened)="setStep(item.step)" hideToggle
            *ngFor="let item of csvColumns; let i = index" formArrayName="selectionArray">
            <mat-expansion-panel-header>
                <mat-panel-title>
                    {{item.title}}
                </mat-panel-title>
                <mat-panel-description>
                    {{i}} {{item.description}}
                </mat-panel-description>
                <fa-icon [icon]="['fas', 'list-ul']" size="lg" style="color: grey"></fa-icon>
            </mat-expansion-panel-header>

            <mat-form-field>
                <mat-label>{{'CSV.DBATTR' | translate}}</mat-label>
                <input matInput placeholder="{{'CSV.CHOOSE' | translate}}" [matAutocomplete]="auto"
                    [formControl]="selectionArray[i]">
                <mat-autocomplete autoActiveFirstOption #auto="matAutocomplete">
                    <mat-option>{{'CSV.NONE' | translate}}</mat-option>
                    <mat-optgroup *ngFor="let group of filteredOptions | async" [label]="group.name">
                        <!-- <fa-icon [icon]="['fas', 'table']" size="lg" class="tree-icons"></fa-icon> -->
                        <mat-option *ngFor="let children of group.children" [value]="children.name">
                            <!-- <fa-icon [icon]="['fas', 'tag']" size="md" class="tree-icons"></fa-icon> -->
                            {{children.name}}
                        </mat-option>
                    </mat-optgroup>
                </mat-autocomplete>
            </mat-form-field>

            <mat-action-row>
                <button *ngIf="item.step !== 0" mat-button color="warn"
                    (click)="prevStep()">{{'CSV.PREV' | translate}}</button>
                <button *ngIf="item.step < csvColumns.length-1" mat-button color="primary"
                    (click)="nextStep()">{{'CSV.NEXT' | translate}}</button>
                <button *ngIf="item.step === csvColumns.length-1" mat-button color="primary"
                    (click)="nextStep()">{{'CSV.END' | translate}}</button>
            </mat-action-row>
        </mat-expansion-panel>
    </form>
</mat-accordion>

Чтобы объяснить этот код: *ngFor="let item of csvColumns; let i = index" он динамически создает столько элементов, сколько содержит мой массив. Например. 5 элементов создают 5 панелей расширения. Мне нужно иметь доступ к значению, которое пользователь выбирает для каждого из этих элементов в этом раскрывающемся списке выбора. Итак, моя идея состоит в том, чтобы создать на шаге, где панели расширения создаются formControls для каждой панели.

Вот почему я хочу использовать formArray. Если вы думаете, что это плохая попытка, скажите мне лучше.

My ts:

export class CSVMappingComponent implements OnInit {

  @Input() headerColumns: Array<string>;

  csvColumns: Array<ExtensionPanelModel>;

  filteredOptions: Observable<DatabaseGroup[]>;
  databaseGroups: DatabaseGroup[];

  formGroup: FormGroup;


  constructor(private builder: FormBuilder) {
    this.formGroup = this.builder.group({
      selectionArray: this.builder.array([])
    });
  }

  // i don't need this but i'm trying everything
  createBox(): FormGroup {
    return this.builder.group({
      name: ''
    });
  }

  get selectionArray() {
    return this.formGroup.get('selectionArray') as FormArray;
  }

  addItems() {
    this.csvColumns = [];
    for (var i = 0; i < this.headerColumns.length; i++) {
      let _step = i.toString();

      this.csvColumns.push({ title: this.translateService.instant('CSV.COLUMN') + ": " + this.headerColumns[i], description: this.translateService.instant('CSV.DESCRIPTION'), step: i });
      this.selectionArray.push(this.createBox());
      // here I really don't know what to do bc I don't need any validator just access the value
      // this.selectionArray.push(this.builder.control(false));
    }
  }

И эта вещь автозаполнения filteredOptions была раньше только с одним formControl, но, конечно, это не может работать.

Ошибки ERROR Error: Cannot find control with unspecified name attribute или что-то вроде ERROR Error: Cannot find control with path: 'selectionArray -> 'когда я использую formControlName="{{selectionArray[i]}}

Скриншот, чтобы вы знали, как это выглядит или должно выглядеть в конце: введите здесь описание изображения


person CptDayDreamer    schedule 12.12.2019    source источник


Ответы (2)


Вы не можете получить доступ к элементам управления formarray как selectionArray[i], попробуйте

<div *ngFor="let control of selectionArray.controls; let i = index">
...
   <input matInput placeholder="{{'CSV.CHOOSE' | translate}}" [matAutocomplete]="auto" formControlName="{{i}}">
...

</div>
person Ininiv    schedule 12.12.2019
comment
Я получаю: ERROR TypeError: control.registerOnChange не является функцией. Я поставил div после строки с ‹mat-expansion-panel› - person CptDayDreamer; 12.12.2019
comment
Замените [formControl] на formControlName={{i}} ‹div *ngFor=let control of selectionArray.controls; пусть я = индекс; › - person Ininiv; 12.12.2019
comment
та же ошибка... хорошо, подождите, я изменил свой ts на this.selectionArray.push(this.builder.control(false)); и это не дает ошибки, но вся структура полностью глючит. Вместо того, чтобы отображать весь мой массив csvColumns, есть только первый, а в раскрывающемся списке указано false. Если я нажму кнопку «Далее» или «Предыдущая», это будет доступно для всех панелей. Таким образом, количество панелей правильное, но они все одинаковые. - person CptDayDreamer; 12.12.2019
comment
Я уже понял проблему там. У меня не может быть ngFor в другом ngFor, потому что ngFor из mat-extension-panel создает каждую панель. Если у вас есть это внутри этой панели, то происходят вещи, которые я вижу. Возможно ли иметь два ngFors или что-то в этом роде? - person CptDayDreamer; 12.12.2019

Два сообщают вам, ребята, какие изменения сработали:

<mat-accordion class="example-headers-align">
    <form [formGroup]="formGroup">
        <div formArrayName="selectionArray">
            <mat-expansion-panel [expanded]="step === item.step" (opened)="setStep(item.step)" hideToggle
                *ngFor="let item of csvColumns; let control of selectionArray.controls; let i = index">
                <mat-expansion-panel-header>
                    <mat-panel-title>
                        {{item.title}}
                    </mat-panel-title>
                    <mat-panel-description>
                        {{i}} {{item.description}}
                    </mat-panel-description>
                    <fa-icon [icon]="['fas', 'list-ul']" size="lg" style="color: grey"></fa-icon>
                </mat-expansion-panel-header>

                <mat-form-field>
                    <mat-label>{{'CSV.DBATTR' | translate}}</mat-label>
                    <input matInput placeholder="{{'CSV.CHOOSE' | translate}}" [matAutocomplete]="auto"
                        formControlName="{{i}}">
                    <mat-autocomplete autoActiveFirstOption #auto="matAutocomplete">
                        <mat-option [value]="null">{{'CSV.NONE' | translate}}</mat-option>
                        <mat-optgroup *ngFor="let group of filteredOptions[i] | async" [label]="group.name">
                            <fa-icon [icon]="['fas', 'table']" size="lg" class="tree-icons"></fa-icon>
                            <mat-option *ngFor="let children of group.children"
                                [value]="[group.name] + ' | ' + [children.name]">
                                <fa-icon [icon]="['fas', 'tag']" size="md" class="tree-icons"></fa-icon>
                                {{children.name}}
                            </mat-option>
                        </mat-optgroup>
                    </mat-autocomplete>
                </mat-form-field>

                <mat-action-row>
                    <button *ngIf="item.step !== 0" mat-button color="warn"
                        (click)="prevStep()">{{'CSV.PREV' | translate}}</button>
                    <button *ngIf="item.step < csvColumns.length-1" mat-button color="primary"
                        (click)="nextStep()">{{'CSV.NEXT' | translate}}</button>
                    <button *ngIf="item.step === csvColumns.length-1" mat-button color="primary"
                        (click)="nextStep()">{{'CSV.END' | translate}}</button>
                </mat-action-row>
            </mat-expansion-panel>
        </div>
    </form>
</mat-accordion>
person CptDayDreamer    schedule 13.12.2019