Dynamisches Formular, das *ngFor verwendet und Werte daraus übermittelt

Lesezeit: 5 Minuten

Benutzer-Avatar
Physikjunge

Ich habe ein Stackblitz als Leitfaden.

Ich möchte eine Liste von Materialkarten anzeigen, auf die ich auf eine Schaltfläche “Bearbeiten” klicke, auf der ich Textfelder bearbeiten kann, und wenn ich auf das Symbol “Speichern” klicke, wird es natürlich gespeichert, indem eine Funktion ausgelöst wird usw.

Ich kämpfe jedoch damit, in den Griff zu bekommen, wie das alles in Angular und der materiellen Natur meiner App funktioniert.

html

<form id="myForm" [formGroup]="thisIsMyForm">
  <mat-card [formGroup]="x" *ngFor="let x of data; let i = index">
    <mat-form-field>
      <label for="{{x.name}}">Name</label>
      <input formControlName="name" id="{{x.name}}" matInput value="{{x.name}}">
    </mat-form-field>
    <mat-form-field>
      <label for="{{x.type}}">Type</label>
      <input formControlName="type" id="{{x.type}}" matInput value="{{x.type}}"/>
    </mat-form-field>
  </mat-card>
</form>

ts

import { Component, ViewChild } from '@angular/core';
import {MatSnackBar} from '@angular/material';
import {FormArray, FormBuilder, FormGroup, Validators} from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  thisIsMyForm: FormGroup

  data = [
    {name:"one", type:"one"},
    {name:"two", type:"two"},
    {name:"three", type:"three"},
  ];

  constructor(private formBuilder: FormBuilder) {}

  onSubmit() {
    // Here I would like to be able to access the values of the 'forms'
  }

}

  • Da es sich um eine ngFor Sie können verwenden FormArray oder QuerySelector das zu tun. Es ist deine Entscheidung.

    – Jacopo Sciampi

    10. Dezember 2018 um 15:15 Uhr


  • @JacopoSciampi könntest du mich bitte auf ein Beispiel verweisen?

    – Physikjunge

    10. Dezember 2018 um 15:16 Uhr

  • Ich mache einen Stackblitz

    – Jacopo Sciampi

    10. Dezember 2018 um 15:29 Uhr

Benutzer-Avatar
Marschall

Sie tauchen sicher ins kalte Wasser und versuchen, eine dynamische reaktive Form im Rahmen einer zu bauen *ngFor ist eine Herausforderung. Ich werde Sie dabei so gut wie möglich begleiten.

Sie müssen ein Array für Steuerelemente erstellen, in Ihrem Konstruktor erstellen Sie Ihre Formulareinstellung formArrayName als leeres Array mit this.formBuild.array([])… nennen Sie das, wie Sie wollen, ich habe es einfach verwendet formArrayName zu Demonstrationszwecken.

Nachdem das Formular mit einem leeren Array-Aufruf instanziiert wurde this.buildForm()

constructor(private formBuilder: FormBuilder) {
    this.thisIsMyForm = new FormGroup({
      formArrayName: this.formBuilder.array([])
    })

    this.buildForm();
  }

In deiner buildForm() iterieren Sie über Ihre data[] und drücken Sie Steuerelemente für jeden Index, während Sie den Standardwert und einen Standardzustand von deaktiviert zuweisen.

 buildForm() {
    const controlArray = this.thisIsMyForm.get('formArrayName') as FormArray;

    Object.keys(this.data).forEach((i) => {
      controlArray.push(
        this.formBuilder.group({
          name: new FormControl({ value: this.data[i].name, disabled: true }),
          type: new FormControl({ value: this.data[i].type, disabled: true })
        })
      )
    })

    console.log(controlArray)
  }

Bitte beachten Sie: console.log(controlArray.controls) ergibt die folgende Ausgabe … jeder Index ist eine FormGroup mit zwei Steuerelementen name und type

0: FormGroup
1: FormGroup
2: FormGroup

In Ihrem HTML müssen Sie eine Containerhierarchie einrichten, die die nachahmt thisIsMyForm Sie haben gerade erstellt.

  • Elternteil:thisIsMyForm
  • Kind:formArrayName
  • Enkel:i as formGroupName

Enkelkind ist wichtig, weil es mit dem Konsolenprotokoll von übereinstimmt controlArray.controls im vorherigen Schritt

<form id="myForm" [formGroup]="thisIsMyForm">
    <div [formArrayName]="'formArrayName'">
        <mat-card *ngFor="let x of data; let i = index">
            <div [formGroupName]="i">

Erstellen Sie Schaltflächen zum Bearbeiten und Speichern basierend auf dem Status der deaktivierten Steuerung

   <button *ngIf="formControlState(i)" (click)="toggleEdit(i)">Enable Edit</button>
    <button *ngIf="!formControlState(i)" (click)="toggleEdit(i)">Save</button>

Erstellen Sie Methoden in der Komponente, um den Index als Argument zu erhalten, und behandeln Sie die Logik, um Schaltflächen auszublenden und den Aktivierungs- und Deaktivierungsstatus von Eingabefeldern umzuschalten.

toggleEdit(i) {
    const controlArray = this.thisIsMyForm.get('formArrayName') as FormArray;
    if(controlArray.controls[i].status === 'DISABLED'){
      controlArray.controls[i].enable()
    }else{
      controlArray.controls[i].disable()
    }
  }

  formControlState(i){
     const controlArray = this.thisIsMyForm.get('formArrayName') as FormArray;
     return controlArray.controls[i].disabled
  }

Übermitteln Sie die Schaltfläche, die den Formularwert von console.log enthält, wenn darauf geklickt wird.

<button [disabled]="thisIsMyForm.get('formArrayName').enabled" (click)="onSubmit()">Submit Form</button>

onSubmit() {
    // Here I would like to be able to access the values of the 'forms'
    console.log(this.thisIsMyForm.value)
  }

Stapelblitz

https://stackblitz.com/edit/dynamic-form-ngfor-otbuzn?embed=1&file=src/app/app.component.ts

  • Achtung, es gibt einen Tippfehler bei Stackblitz. Es sagt ‘formControlState’ statt ‘formControlState’. Auch dieser Beitrag ist super hilfreich! Vielen Dank!

    – Grant Curell

    18. Mai 2020 um 20:59 Uhr

  • @GrantCurell guter Fang! es wurde korrigiert. Nichts geht über das Kopieren und Einfügen eines Tippfehlers. Kein Problem, ich freue mich, dass Sie diese Informationen hilfreich fanden.

    – Marschall

    18. Mai 2020 um 21:30 Uhr

Mach es mit QueryList:

Ihr HTML (dies ist ein Beispiel):

<ng-container *ngFor="let x of data; let i = index">
  <div class="ctr">
    <span #names class="item">{{x.name}}</span>
    <span #types class="item">{{x.type}}</span>
    <span class="button" (click)="showData(i)">Show data</span>
  </div>

</ng-container>

<h2>Selected values: </h2>
Selected name: {{selectedName}} <br>
Selected type: {{selectedType}}

etwas CSS nur für den Stil

.ctr{
  display: flex;
  flex-direction: row;
  margin-bottom: 20px;
}

.item{
  margin-right:40px;
}

.button{
  border: 1px solid black;
  padding: 2px 5px 2px 5px;
  cursor: pointer;
}

die Komponente:

import { Component, QueryList, ViewChildren } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  @ViewChildren('names') names:QueryList<any>;
  @ViewChildren('types') types:QueryList<any>;

  selectedName: string;
  selectedType: string;

  data = [
    {name:"one", type:1},
    {name:"two", type:2},
    {name:"three", type:3},
  ];

  showData(index){
    let namesArray = this.names.toArray();
    let typesArray = this.types.toArray();

    this.selectedName = namesArray[index].nativeElement.innerHTML;
    this.selectedType = typesArray[index].nativeElement.innerHTML;
  }
}

Stackblitz funktioniert: https://stackblitz.com/edit/angular-j2n398?file=src%2Fapp%2Fapp.component.ts

  • Wie würde man dies verwenden, um Daten von a form?

    – Physikjunge

    10. Dezember 2018 um 15:57 Uhr

  • Ich glaube, ich habe es im Griff, nachdem ich mir Ihren Blitz genauer angesehen habe, aber wenn ich auf Probleme stoße, werde ich Sie benachrichtigen 🙂

    – Physikjunge

    10. Dezember 2018 um 15:59 Uhr

  • Ich bin nicht vertraut, wie man es “gut” macht FormArray, weil ich es nicht wirklich mag. Aber vor ein paar Monaten habe ich versucht, es zu verstehen, und dieser Link hat mir sehr gut geholfen: stackblitz.com/edit/wr-angular-nested-form-array

    – Jacopo Sciampi

    10. Dezember 2018 um 16:06 Uhr

1005740cookie-checkDynamisches Formular, das *ngFor verwendet und Werte daraus übermittelt

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy