web-dev-qa-db-fra.com

Impossible de patcher des données sur FormArray

Impossible de corriger les valeurs dans FormArray resultList.

Quelqu'un peut-il m'expliquer ce qui me manque?

Fichier TS:

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

@Component({
  selector: 'app-container',
  templateUrl: './container.component.html',
  styleUrls: ['./container.component.css']
})

export class ContainerComponent implements OnInit {

  studList: Student[] = [];
  myform: FormGroup = new FormGroup({
    firstName: new FormControl('', [Validators.required, Validators.minLength(4)]),
    lastName: new FormControl(),
    gender: new FormControl('male'),
    dob: new FormControl(),
    qualification: new FormControl(),
    resultList: new FormArray([])
  });    

  onSave() {
    let stud: Student = new Student();
    stud.firstName = this.myform.get('firstName').value;
    stud.lastName = this.myform.get('lastName').value;
    stud.gender = this.myform.get('gender').value;
    stud.dob = this.myform.get('dob').value;
    stud.qualification = this.myform.get('qualification').value;
    this.studList.Push(stud);
    this.myform.controls.resultList.patchValue(this.studList);
    console.log(JSON.stringify(this.studList));
  }

  ngOnInit() {
  }
}

Modèle:

export class Student {
    public firstName: String;
    public lastName: string;
    public gender: string;
    public dob: string;
    public qualification: string;
}

HTML:

    <div class="container">
        <h3>Striped Rows</h3>
        <table class="table table-striped" formArrayName="resultList">
            <thead>
                <tr>
                    <th>Firstname</th>
                </tr>
            </thead>
            <tbody>
                <tr *ngFor="let item of myform.controls.resultList.controls; let i = index" [formGroupName]="i">
                    <td><p formControlName="firstName"></p></td>
                </tr>
            </tbody>
        </table>
    </div>

this.studList JSON:

[  
   {  
      "firstName":"santosh",
      "lastName":"jadi",
      "gender":"male",
      "dob":"2018-03-31T18:30:00.000Z",
      "qualification":"BE"
   },
   {  
      "firstName":"santosh",
      "lastName":"jadi",
      "gender":"male",
      "dob":"2018-03-31T18:30:00.000Z",
      "qualification":"BE"
   }
]
14
Santosh Jadi

Par votre question, vous souhaitez ajouter un nouveau Student à resultList. Tout d'abord, vous devez savoir que FormArray est un tableau de AbstractControl . Vous pouvez ajouter au tableau uniquement le type de AbstractControl pas les autres. Pour simplifier la tâche, préférez utiliser FormBuilder:

 constructor(private fb: FormBuilder) {}

  createForm() {

    this.myform = this.fb.group({
      firstName: ['', [Validators.required, Validators.minLength(4)]],
      lastName: [],
      gender: ['male'],
      dob: [],
      qualification: [],
      resultList: new FormArray([])
    });
  }

Comme vous pouvez le voir avant de remplir resultList FormArray, il est mappé sur FormGroup :

onSave() {
    let stud: Student = new Student();
    stud.firstName = 'Hello';
    stud.lastName = 'World';
    stud.qualification = 'SD';
    this.studList.Push(stud);

    let studFg = this.fb.group({
      firstName: [stud.firstName, [Validators.required, Validators.minLength(4)]],
      lastName: [stud.lastName],
      gender: [stud.gender],
      dob: [stud.dob],
      qualification: [stud.qualification],
    })
     let formArray = this.myform.controls['resultList'] as FormArray;
    formArray.Push(studFg);
    console.log(formArray.value)
  }

FormBuilder - Crée un AbstractControl à partir d'une configuration spécifiée par l'utilisateur.

C'est essentiellement du sucre syntaxique qui raccourcit le nouveau FormGroup () , le nouveau FormControl () , et nouveau FormArray () passe-partout qui peut s'accumuler dans des formes plus grandes.

En outre, en html formControlName lié à <p> élément, Ce n'est pas une entrée et vous ne pouvez pas lier pour ne pas former des éléments comme div/p/span ...:

 <tbody>
                <tr *ngFor="let item of myform.controls.resultList.controls; let i = index" [formGroupName]="i">
                    <td><p formControlName="firstName"></p></td> <==== Wrong element 
                </tr>
</tbody>

Donc, je pense que vous voulez simplement montrer les élèves ajoutés dans le tableau. Ensuite, parcourez studList et montrez sa valeur dans le tableau:

<tbody>
                <tr *ngFor="let item of studList; let i = index" [formGroupName]=i>
                    <td>
                        <p> {{item.firstName}} </p>
                    </td>
                </tr>
</tbody>

Valeur de correction

Faites attention lorsque vous patchez la baie. Parce que patchValue of FormArray corrige les valeurs par l'index :

 patchValue(value: any[], options: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
    value.forEach((newValue: any, index: number) => {
      if (this.at(index)) {
        this.at(index).patchValue(newValue, {onlySelf: true, emitEvent: options.emitEvent});
      }
    });
    this.updateValueAndValidity(options);
  }

Donc, le code en dessous corrige l'élément à index = 0 : Première valeur indexée de this.myform.controls['resultList'] as FormArray sera remplacé par:

let stud1 = new Student();

stud1.firstName = 'FirstName';
stud1.lastName = 'LastName';
stud1.qualification = 'FFF';
formArray.patchValue([stud1]);

Votre cas ne fonctionne pas car patchValue nécessite certains contrôles dans le tableau. Dans votre cas, il n'y a aucun contrôle dans le tableau. Regardez le code source.

Démo StackBlitz

11
Yerkon

Essayez d'abord avec ces étapes et assurez-vous que vous êtes sur la bonne voie

Parce que dans votre scénario, vous corrigez l'objet sur formArray, vous devez donc d'abord analyser cet objet et vérifier une fois que vous avez importé ReactiveFormsModule dans votre app.module.ts.

6
Omkar Jadhav

vous devez co comme ceci, le code est tiré de angular.io , vous devez faire setcontrol qui fera ou ira bien que le lien existe pour le même code qu'il utilise le tableau d'adresses

 this.setAddresses(this.hero.addresses);

  setAddresses(addresses: Address[]) {
    const addressFGs = addresses.map(address => this.fb.group(address));
    const addressFormArray = this.fb.array(addressFGs);
    this.heroForm.setControl('secretLairs', addressFormArray);
  }
4
Pranay Rana

Je préfère utiliser FormBuilder pour créer un formulaire.

export class ComponentName implements OnInit {
    form: FormGroup;
    constructor(private fb: FormBuilder){}

    ngOnInit() {
       this.buildForm();
    }

    buildForm() {
        this.form = this.fb.group({
            firstName: '',
            lastName: '',
            ...
            resultList: this.fb.array([])
        });
    }
}

Je crois que la liste des studs sera obtenue via un appel API comme un tableau observable plutôt que statique. Supposons que nous donnons les données comme suit.

resultModel = 
{
    firstName: "John",
    lastName: "Doe",
    ....
    resultList: [
       {
            prop1: value1,
            prop2: value2,
            prop3: value3
       },
       {
            prop1: value1,
            prop2: value2,
            prop3: value3
       }
       ...
    ]
}

Une fois les données disponibles, nous pouvons corriger les valeurs comme suit:

patchForm(): void {
        this.form.patchValue({
            firstName: this.model.firstName,
            lastName: this.model.lastName,
            ...
        });

        // Provided the FormControlName and Object Property are same
        // All the FormControls can be patched using JS spread operator as 

        this.form.patchValue({
            ...this.model
        });

        // The FormArray can be patched right here, I prefer to do in a separate method
        this.patchResultList();
}

// this method patches FormArray
patchResultList() {
    let control = this.form.get('resultList') as FormArray;
    // Following is also correct
    // let control = <FormArray>this.form.controls['resultList'];

   this.resultModel.resultList.forEach(x=>{
        control.Push(this.fb.group({
            prop1: x.prop1,
            prop2: x.prop2,
            prop3: x.prop3,

        }));
    });
}
2
20B2

Le tableau ne contient pas de méthode patchValue. Vous devez parcourir les contrôles et patchValue chacun d'eux séparément.

1
ritaj

J'utilise formgroup dans formarray comme:

this.formGroup = new FormGroup({
      clientCode: new FormControl('', []),
      clientName: new FormControl('', [Validators.required, Validators.pattern(/^[a-zA-Z0-9 _-]{0,50}$/)]),
      type: new FormControl('', [Validators.required]),
      description: new FormControl('', []),
      industry: new FormControl('', []),
      website: new FormControl('', [Validators.required, Validators.pattern(this.settings.regex.website)]),
      businessEmail: new FormControl('', [Validators.pattern(this.settings.regex.email)]),
      clients: this._formBuilder.array([this._formBuilder.group({
        contactPerson: new FormControl('', [Validators.required]),
        contactTitle: new FormControl('', [Validators.required]),
        phoneNumber: new FormControl('', [Validators.required, Validators.pattern(this.settings.regex.phone)]),
        emailId: new FormControl('', [Validators.required, Validators.pattern(this.settings.regex.email)]),
        timeZone: new FormControl('', [Validators.required, Validators.pattern(this.settings.zipCode), Validators.minLength(5), Validators.maxLength(12)])
      })])
    })

Pour la valeur du patch, j'utilise la méthode ci-dessous comme:

let control = _this.formGroup.get('clients') as FormArray
        clients.forEach(ele => {
          control.Push(_this._formBuilder.group({
            contactPerson: new FormControl(ele.client_name, [Validators.required]),
            contactTitle: new FormControl(ele.contact_title, [Validators.required]),
            phoneNumber: new FormControl(ele.phone_number, [Validators.required, Validators.pattern(_this.settings.regex.phone)]),
            emailId: new FormControl(ele.email_id, [Validators.required, Validators.pattern(_this.settings.regex.email)]),
            timeZone: new FormControl(ele.timezone, [Validators.required, Validators.pattern(_this.settings.zipCode), Validators.minLength(5), Validators.maxLength(12)])
          }))
        });

En utilisant cette méthode, nous pouvons également valider le champ imbriqué.

J'espère que cela peut vous aider.

0
Pankaj Bhandarkar