ОШИБКА TypeError: Невозможно прочитать свойство 'invalid' из undefined при попытке отобразить FormArray для FormGroups в Angular - PullRequest
0 голосов
/ 19 марта 2020

У меня есть предметы, которые можно изменить в соответствии с потребностями клиента. Чтобы взять список элементов с различными модификациями, я решил создать форму, в которую они могут добавлять столько элементов, сколько они хотят, и выбирать спецификации для каждого из них. Для этого мне нужно создать FormArray из FormGroups. Все компилируется так, как должно быть, но у меня появляется ошибка, когда программа пытается отобразить форму: ОШИБКА TypeError: Невозможно прочитать свойство 'invalid' из undefined

Вот код моего app.component. ts (items и addItem ())

import {FormArray, FormControl, FormGroup, Validators} from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  form: FormGroup

  ngOnInit() {
    this.form = new FormGroup({
      companyName: new FormControl('', Validators.required),
      items: new FormArray([])
    })
    this.addItem()
  }

  submit() {
    if(this.form.valid){
      console.log('Form submited', this.form)
      const formData = {...this.form.value}

      console.log('Form Data: ', formData)
    }
  }

  controlSelectChanged() {
    if(this.form.get('item').get('controlSelect').value == 'Ручное'){

    }
  }

  addItem() {
    const item = new FormGroup({
      modelSelect: new FormControl('', Validators.required),
      quantity: new FormControl('', Validators.required),
      width: new FormControl('', Validators.required),
      height: new FormControl('', Validators.required),
      colorSelect: new FormControl('', Validators.required),
      factorySelect: new FormControl('', Validators.required),
      articleSelect: new FormControl('', Validators.required),
      articleSelect2: new FormControl('', Validators.required),
      controlSelect: new FormControl('', Validators.required),
      controlSideSelect: new FormControl('', Validators.required),
      controlFactorySelect: new FormControl('', Validators.required),
      controlAcceptorSelect: new FormControl('', Validators.required),
      automaticFactorySelect: new FormControl('', Validators.required),
      quantityPult: new FormControl('', Validators.required),
      automaticAdditionSelect: new FormControl('', Validators.required),
      notes: new FormControl(''),
    });
    (this.form.get('items') as FormArray).push(item)
    console.log(this.form.get('items'))
  }
}

, а вот фрагмент кода, который отображает этот массив из app.component. html

<form [formGroup]="form" (ngSubmit)="submit()">
        <div class="form-group invis">
          <label for="inputCompanyName">Название вашей компании</label>
          <input type="email" class="form-control" id="inputCompanyName" formControlName="companyName" aria-describedby="companyNameHelp" placeholder="Введите название компании">
          <small id="companyNameHelp" class="form-text text-muted">Это поле обязательно для заполнения.</small>
          <button type="button" class="btn btn-primary mt-20" [disabled]="form.controls['companyName'].invalid">Далее</button>
        </div>

<div *ngFor="let item of form.get('items')" class="form-group">
          <ng-container [formGroupName]="item">
          <div class="form-row">
            <div class="form-group col">
              <label for="modelSelect">Модель</label>
              <select class="form-control" id="modelSelect" formControlName="modelSelect">
                <option>ASN130</option>
                <option>ASN</option>
                <option>ASN110 cab</option>
                <option>ASN 110 GPZ TENS</option>
                <option>Зашивка на люверсах</option>
              </select>
            </div>

            <div class="col-md-1">
              <label for="quantity">Кол-во</label>
              <input type="text" class="form-control" id="quantity" placeholder="-" formControlName="quantity">
            </div>

            <div class="col-md-1">
              <label for="width">Ширина</label>
              <input type="text" class="form-control" id="width" placeholder="-" formControlName="width">
            </div>

            <div class="col-md-1">
              <label for="height">Высота</label>
              <input type="text" class="form-control" id="height" placeholder="-" formControlName="height">
            </div>

            <div class="form-group col">
              <label for="colorSelect">Цвет профилей</label>
              <select class="form-control" id="colorSelect" formControlName="colorSelect">
                <option>9003 Белый</option>
                <option>9004 Черный</option>
                <option>8017 Коричневый</option>
                <option>7024 Антрацит</option>
                <option>1024 Бежевый</option>
              </select>
            </div>

            <div class="form-group col">
              <label for="factorySelect">Производитель тента</label>
              <select class="form-control" id="factorySelect" formControlName="factorySelect">
                <option>COPACO</option>
                <option>DICKSON</option>
                <option>М8</option>
              </select>
            </div>

            <div class="form-group col">
              <label for="articleSelect">Артикул тента</label>
              <select class="form-control" id="articleSelect" formControlName="articleSelect">
                <option>COPACO</option>
                <option>DICKSON</option>
                <option>М8</option>
              </select>
            </div>

            <div class="form-group col">
              <label for="articleSelect2">Сторона</label>
              <select class="form-control" id="articleSelect2" formControlName="articleSelect2">
                <option>Back со стороны короба</option>
                <option>Front со стороны короба</option>
                <option>Back со стороны подворота</option>
                <option>Front со стороны подворота</option>
              </select>
            </div>

          </div>
          <div class="form-row">
            <div class="form-group col">
              <label for="controlSelect">Управление</label>
              <select class="form-control" id="controlSelect" formControlName="controlSelect" (change)="controlSelectChanged()">
                <option>Ручное</option>
                <option>Автоматическое</option>
              </select>
            </div>

            <div class="form-group col">
              <label for="controlSideSelect">Сторона управления </label>
              <select class="form-control" id="controlSideSelect" formControlName="controlSideSelect">
                <option>Справа</option>
                <option>Слева</option>
              </select>
            </div>

            <div class="form-group col">
              <label for="controlFactorySelect">Производитель привода</label>
              <select class="form-control" id="controlFactorySelect" formControlName="controlFactorySelect">
                <option>Дорхан</option>
                <option>Somfy</option>
              </select>
            </div>

            <div class="form-group col">
              <label for="controlAcceptorSelect">Вид привода</label>
              <select class="form-control" id="controlAcceptorSelect" formControlName="controlAcceptorSelect">
                <option>Без приемника</option>
                <option>Cо встроенным приемником </option>
              </select>
            </div>
          </div>
          <div class="form-row">
            <div class="form-group col">
              <label for="automaticFactorySelect">Производитель автоматики</label>
              <select class="form-control" id="automaticFactorySelect" formControlName="automaticFactorySelect">
                <option>Дорхан</option>
                <option>Somfy</option>
              </select>
            </div>

            <div class="col-lg-2">
              <label for="quantityPult">Кол-во пультов</label>
              <input type="text" class="form-control" id="quantityPult" placeholder="-" formControlName="quantityPult">
            </div>

            <div class="form-group col">
              <label for="automaticAdditionSelect">Дополнительная автоматика</label>
              <select class="form-control" id="automaticAdditionSelect" formControlName="automaticAdditionSelect">
                <option>Нет</option>
                <option>Датчик ветра</option>
              </select>
            </div>

            <div class="col">
              <label for="notes">Примечания</label>
              <textarea class="form-control" id="notes" rows="3" formControlName="notes"></textarea>
            </div>
          </div>
          </ng-container>
        </div>
<div class="form-row justify-content-md-center">
          <button type="button" class="btn btn-primary mt-30 addNewItemButton" (click)="addItem()">Добавить новый товар</button>
        </div>
<button type="button" class="btn btn-primary mt-20" [disabled]="form.controls['item'].invalid">Далее</button>


        <button type="submit" class="btn btn-primary mt-20" [disabled]="form.invalid">submit</button>
      </form>

Заранее спасибо!

Ответы [ 2 ]

1 голос
/ 19 марта 2020

Рабочий пример вы можете найти здесь:

https://stackblitz.com/edit/angular-obnxyi

  1. Я перерабатываю компонент, используя formBuilder, чтобы получить код очистки.
  2. В *NgFor правильный способ доступа к элементам управления FormArray использует form.get('items').controls с controls, которые дают вам доступ к массиву элементов управления
  3. Я переместил l oop в ng-container, чтобы установить свойство formArrayName внутри родительского элемента повторяющегося тега. Итак, теперь у вас есть <div formArrayName="items" class="form-group">
0 голосов
/ 19 марта 2020

Ваша форма HTML должна отражать структуру вашей формы.

Так что, если вы создаете следующую форму:

ngOnInit() {
  this.form = new FormGroup({
    companyName: new FormControl('', Validators.required),
    items: new FormArray([
      new FormGroup({
        modelSelect: new FormControl('', Validators.required)
      }),
      new FormGroup({
        modelSelect: new FormControl('', Validators.required)
      })
    ])
  });
}

onSubmit() {
  const models = this.form.get('items')
    .controls
    .map(x => x.get('modelSelect').value);
  console.log(models);
}

Тогда минимальный HTML вам нужен следующий:

<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <input formControlName="companyName" />
  <div formArrayName="items">
    <ng-container *ngFor="let control of form.get('items').controls; index as i">
      <div [formGroupName]="i">
        <input formControlName="modelSelect" />
      </div>
    </ng-container>
  </div>
</form>

Обратите внимание, как директивы формы отражают структуру FormGroup. Вы связываете элементы FormArray, используя [formGroupName]="i", если ваш массив состоит из групп форм.

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