Angular: проблема в добавлении динамически генерируемых данных поля ввода для события (изменения) - PullRequest
0 голосов
/ 05 июля 2019

У меня есть возможность отправлять динамически сгенерированные поля ввода по нажатию кнопки.

Я воссоздаю проблему на stackblitz для лучшего понимания.

Вэто приложение, когда я ввожу resourceQuantity, поля resourceId генерируются динамически.Моя задача состоит в том, чтобы идентифицировать эти поля по отдельности и отправить их на стороне сервера одним нажатием кнопки.

Это решение, которое я нашел на stackblitz, аналогично, но в моей проблеме я не убираю и не добавляю нажатия кнопок, а вместо этого (изменяю) событие.

Вот код HTML :

<mat-form-field>
    <input  matInput type="number" formControlName="resourceQuantity" [(ngModel)]="resourceQuantity" placeholder="Enter Resource Quantity" (change)="somethingChanged()"/> 
</mat-form-field><br/><br/>
<div>
    <ul>
        <li *ngFor="let item of counter(resourceQuantity)">
            <input  matInput type="number" placeholder="Enter Resource Number" formControlName="resourceId"/> 
        </li>       
    </ul>
</div>

А вот код TS :

  ngOnInit() {
    this.form = new FormGroup({
            'employeeId': new FormControl(null, {validators: [Validators.required]}),
            'employeeName': new FormControl(null, {validators: [Validators.required]}),
            'resourceQuantity': new FormControl(null, {validators: [Validators.required]}),
            'resourceId': new FormControl(null, {validators: [Validators.required]})
    });
  }

  somethingChanged() {
      console.log(this.resourceQuantity);
  }

  counter(i: number) {
      return new Array(i);
  }

Пожалуйстадайте мне знать лучшее решение моей проблемы.Спасибо.

Ответы [ 4 ]

1 голос
/ 05 июля 2019

Я бы также настроил свою модель сотрудника для включения массива ресурсов;

import { Resource } from './resource.model';

export interface Employee {
    employeeId: number;
    employeeName: string;
    resourceQuantity: number;
    resourceIds: Resource[];
}

Тогда вашему ресурсу просто необходим идентификатор:

export interface Resource {
    resourceId: number;
}
1 голос
/ 05 июля 2019

Вы должны использовать FormArray для решения этой проблемы. StackBlitz Demo

1.Измените ваш resourceId с FormControl на FormArray, как следует.

 'resourceId': new FormArray([])

2. Измените свой метод counter, чтобы вставить FormControl в FormArray на основе Количество ресурсов , этот метод вызывается, когда событие изменения срабатывает в Количество ресурсов . Он получает значение resourceQuantity из FormGroup, а затем очищает значение FormArray. После этого он перебирает индекс для динамического создания FormControl и вставляет его в FormArray

counter() {
    const index = parseInt(this.form.value.resourceQuantity);
    (this.form.controls.resourceId as FormArray).clear();
    for(let i = 0; i < index; i++) {
      const formControl = new FormControl();
      (this.form.controls.resourceId as FormArray).push(formControl);
    }
}

3.использование геттеров для легкого доступа к элементам управления

  get formControls(): any {
    return this.form.controls;
  }

  get resourceIDControls(): any {
    return this.form.controls.resourceId['controls'];
  }

4.Измените ваш HTML для циклического перебора FormArray и установите FormControlName динамически.

<div formArrayName="resourceId">
     <ul>
         <li *ngFor="let item of resourceIDControls; let i = index">
             <input  matInput type="number" placeholder="Enter Resource Number" [formControlName]="i"/> 
         </li>       
     </ul>
 </div>

Sample Inputs - Demo

Form Value after the submission will look like this

1 голос
/ 05 июля 2019

Избегайте использования ngModel и formControl вместе. Вы можете использовать formArray вместе с функциями получения в вашем компоненте, чтобы получить ваш результат.

Редактировать : я отредактировал свой код, чтобы отразить запрошенное вами изменение, подписавшись на valueChanges на resourceQuantity formControl и сгенерировав formArray, когда он обнаружит изменение. Это создает ресурсы в режиме реального времени.

Редактировать : Не забудьте отписаться от valueChanges, чтобы предотвратить утечку памяти. Я обновил свой Stackblitz, чтобы показать то же самое.

Вот рабочий пример для StackBlitz

1 голос
/ 05 июля 2019

Здесь у вас есть идеальный вариант использования для formArray ... единственное отличие состоит в том, что вам нужно добавить formControls на основе значения, которое вводится в поле resourceQuantity.

релевантный HTML :

<mat-card>
    <form [formGroup]="form" (submit)="add()">
        <mat-form-field>
            <input matInput type="number" formControlName="employeeId" placeholder="Enter Employee Id" (change)='updateFormString()'/>
      </mat-form-field><br/><br/>
      <mat-form-field>
            <input matInput formControlName="employeeName" placeholder="Enter Employee Name" (change)='updateFormString()'/>
      </mat-form-field><br/><br/>
      <mat-form-field>
            <input  matInput type="number" formControlName="resourceQuantity" [(ngModel)]="resourceQuantity" placeholder="Enter Resource Quantity" (change)="somethingChanged()"/> 
        </mat-form-field><br/><br/>
           <!--
             <div>
                <ul>
                    <li *ngFor="let item of counter(resourceQuantity)">
                        <input  matInput type="number" placeholder="Enter Resource Number" formControlName="resourceId"/> 
                    </li>       
                </ul>
            </div>
            -->
        <div fxLayout>
            <div>
                <button
                    mat-raised-button
                    color="accent" [disabled] = "form.invalid">Save
                </button>
            </div>
        </div>

        <div formArrayName='resourceId'>
          <br/>
          <div *ngFor='let item of resourceId.controls; let i = index'>
            <input type='text' [formControlName]="i" >
          </div>
        </div>

    </form>
</mat-card>

{{formString}}

релевантный TS :

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators, FormArray, FormBuilder } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  form: FormGroup;
  resourceQuantity: any;
  formString: string;

  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    this.form = this.fb.group({
      'employeeId': new FormControl(null, { validators: [Validators.required] }),
      'employeeName': new FormControl(null, { validators: [Validators.required] }),
      'resourceQuantity': new FormControl(null, { validators: [Validators.required] }),
      //'resourceId': new FormControl(null, {validators: [Validators.required]}),
      resourceId: this.fb.array([
        this.fb.control('test entry default')
      ])
    });
  }

  updateFormString() {
    this.formString = JSON.stringify(this.form.value);
  }

  somethingChanged() {
    for (var i = 1; i < this.resourceQuantity; i++) {
      this.addResource();
    }
    this.updateFormString();
  }

  get resourceId() {
    return this.form.get('resourceId') as FormArray;
  }

  addResource() {
    this.resourceId.push(this.fb.control('test entry additional'));
  }

  counter(i: number) {
    return new Array(i);
  }
}

рабочий стекаблитц доступен здесь

...