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'
}
}
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
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
Da es sich um eine
ngFor
Sie können verwendenFormArray
oderQuerySelector
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