Ошибка при создании динамической формы из json Не удается найти элемент управления с именем: «данные» - PullRequest
4 голосов
/ 28 июня 2019

Я использую приложение angular 7 и пишу универсальный динамический создатель форм.Я использую реактивные формы и ng-template and <ng-container *ngTemplateOutlet> для рекурсивного отображения элемента формы. Код проекта можно увидеть Здесь .

Но я сталкиваюсь со следующей ошибкой

ERROR Error: Cannot find control with name: 'data'
    at _throwError (forms.js:1775)
    at setUpControl (forms.js:1683)
    at FormGroupDirective.push../node_modules/@angular/forms/fesm5/forms.js.FormGroupDirective.addControl (forms.js:4532)
    at FormControlName.push../node_modules/@angular/forms/fesm5/forms.js.FormControlName._setUpControl (forms.js:5030)
    at FormControlName.push../node_modules/@angular/forms/fesm5/forms.js.FormControlName.ngOnChanges (forms.js:4980)
    at checkAndUpdateDirectiveInline (core.js:9239)
    at checkAndUpdateNodeInline (core.js:10507)
    at checkAndUpdateNode (core.js:10469)
    at debugCheckAndUpdateNode (core.js:11102)
    at debugCheckDirectivesFn (core.js:11062)

Но если я вижу свой объект formGroup, я вижу элемент управления с данными в качестве имени элемента управления, как показано ниже.

enter image description here

Чтоэто ошибка, которую я делаю?Пожалуйста, помогите.

Воспроизведение проблемы Здесь Stabblitz

1 Ответ

4 голосов
/ 01 июля 2019

Вы правы, здесь проблема с ng-шаблоном.

Директива

FormControlName в значительной степени опирается на иерархию элементов над текущим элементом для определения FormControl. Так как вы используете ngTemplateOutlet, эта иерархия перепуталась, и Angular не может найти родительские FormGroup или FormArray элементы управления.

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

С другой стороны, вы можете заставить его работать с ngTemplateOutlet, если будете использовать директиву FormControl . Вам нужно только убедиться, что вы правильно указали элемент input.

Вот как это можно сделать:

<form [formGroup]="form">
    <ng-container *ngTemplateOutlet="controlList; context: {controls: schema, path: []}"></ng-container>

    <ng-template #controlList let-controls="controls" let-path="path" let-isArray="isArray">

        <ng-container *ngFor="let control of controls; let i = index;">
            <ng-container *ngIf="control?.type === 'simple'">
                <div class="control">
                    <label>
              {{ control.label }}
              <input type="text" [formControl]="form.get(isArray ? path.concat(i, control.name) : path.concat(control.name))"> 
            </label>
                </div>
            </ng-container>
            <ng-container *ngIf="['object', 'array'].indexOf(control.type) > -1">
                <fieldset>
          <legend>{{control.name}}</legend>
                    <ng-container
                        *ngTemplateOutlet="controlList; context: {controls: control.items, isArray: control.type === 'array', path: isArray ? path.concat(i, control.name) : path.concat(control.name)}">
                    </ng-container>
                </fieldset>
            </ng-container>
        </ng-container>

    </ng-template>
</form>

Ключевым моментом здесь является получение правильного path для целевого элемента управления, который я передаю как часть контекста следующему дочернему уровню.

Также, если вы хотите сгенерировать вложенные элементы бесконечной структуры, вам следует изменить код для построения FormGroup:

ngOnInit() {
  this.schema = data.start.fields.schema;
  this.form = this.createFormGroup(this.schema);
} 

createFormGroup(items) {
  let group: { [controlId: string]: AbstractControl; } = {};

  items.forEach((item) => group[item.name] = this.createFormControl(item));

  return this.fb.group(group);
}

createFormControl(item) {
  if (item.type === 'array') {
    return this.fb.array(item.items.map((subItem) => {
      return this.fb.group({
        [subItem.name]: this.createFormControl(subItem)
      })
    }));
  } else if (item.type === 'object') {
    return this.createFormGroup(item.items);
  } else {
    return this.fb.control(item.value, []);
  }
}

Ng-run Пример

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