Je suis nouveau sur Angular 2 et j'ai décidé que la meilleure façon d'apprendre serait de passer par les guides officiels Angular.
J'ai parcouru le Guide des formulaires réactifs https://angular.io/guide/reactive-forms
lien de démonstration: https://stackblitz.com/angular/jammvmbrpxle
Bien que le contenu soit globalement bon, je ne sais pas comment mettre en œuvre un formulaire plus complexe. Dans l'exemple donné, chaque héros a le potentiel pour de nombreuses adresses. Une adresse elle-même est un objet plat.
Que se passe-t-il si Adresses contenait des informations supplémentaires telles que la couleur et le type de pièces situées à l'adresse?.
export class Address {
street = '';
city = '';
state = '';
Zip = '';
rooms = Room[];
}
export class Room {
type = '';
}
afin que le modèle de formulaire ressemble à ceci ...
createForm() {
this.heroForm = this.fb.group({
name: '',
secretLairs: this.fb.array([
this.fb.group({
street: '',
city: '',
state: '',
Zip: '',
rooms: this.fb.array([
this.fb.group({
type: ''
})]),
})]),
power: '',
sidekick: ''
});
}
EDIT - Code finalisé qui fonctionne avec ngOnChanges
hero-detail.component.ts
createForm() {
this.heroForm = this.fb.group({
name: '',
secretLairs: this.fb.array([
this.fb.group({
street: '',
city: '',
state: '',
Zip: '',
rooms: this.fb.array([
this.fb.group({
type: ''
})
])
})
]),
power: '',
sidekick: ''
});
}
ngOnChanges() {
this.heroForm.reset({
name: this.hero.name,
});
this.setAddresses(this.hero.addresses);
}
setAddresses(addresses: Address[]) {
let control = this.fb.array([]);
addresses.forEach(x => {
control.Push(this.fb.group({
street: x.street,
city: x.city,
state: x.state,
Zip: x.Zip,
rooms: this.setRooms(x) }))
})
this.heroForm.setControl('secretLairs', control);
}
setRooms(x) {
let arr = new FormArray([])
x.rooms.forEach(y => {
arr.Push(this.fb.group({
type: y.type
}))
})
return arr;
}
hero-detail.component.html (la partie du tableau de formulaire imbriqué)
<div formArrayName="secretLairs" class="well well-lg">
<div *ngFor="let address of heroForm.get('secretLairs').controls; let i=index" [formGroupName]="i" >
<!-- The repeated address template -->
<h4>Address #{{i + 1}}</h4>
<div style="margin-left: 1em;">
<div class="form-group">
<label class="center-block">Street:
<input class="form-control" formControlName="street">
</label>
</div>
<div class="form-group">
<label class="center-block">City:
<input class="form-control" formControlName="city">
</label>
</div>
<div class="form-group">
<label class="center-block">State:
<select class="form-control" formControlName="state">
<option *ngFor="let state of states" [value]="state">{{state}}</option>
</select>
</label>
</div>
<div class="form-group">
<label class="center-block">Zip Code:
<input class="form-control" formControlName="Zip">
</label>
</div>
</div>
<br>
<!-- End of the repeated address template -->
<div formArrayName="rooms" class="well well-lg">
<div *ngFor="let room of address.get('rooms').controls; let j=index" [formGroupName]="j" >
<h4>Room #{{j + 1}}</h4>
<div class="form-group">
<label class="center-block">Type:
<input class="form-control" formControlName="type">
</label>
</div>
</div>
</div>
</div>
<button (click)="addLair()" type="button">Add a Secret Lair</button>
</div>
Ce n'est pas très différent d'avoir un formarray imbriqué. En gros, vous venez de dupliquer le code que vous avez ... avec un tableau imbriqué :) Alors voici un exemple:
myForm: FormGroup;
constructor(private fb: FormBuilder) {
this.myForm = this.fb.group({
// you can also set initial formgroup inside if you like
companies: this.fb.array([])
})
}
addNewCompany() {
let control = <FormArray>this.myForm.controls.companies;
control.Push(
this.fb.group({
company: [''],
// nested form array, you could also add a form group initially
projects: this.fb.array([])
})
)
}
deleteCompany(index) {
let control = <FormArray>this.myForm.controls.companies;
control.removeAt(index)
}
Il s'agit donc de l'ajout et de la suppression pour le tableau de formulaire le plus à l'extérieur. L'ajout et la suppression de formgroups au tableau de formulaire imbriqué ne font que dupliquer le code. Où du modèle nous passons le formgroup actuel à quel tableau vous voulez ajouter (dans ce cas) un nouveau projet/supprimer un projet.
addNewProject(control) {
control.Push(
this.fb.group({
projectName: ['']
}))
}
deleteProject(control, index) {
control.removeAt(index)
}
Et le modèle de la même manière, vous parcourez votre formarray externe, puis à l'intérieur de celui-ci, votre tableau de formulaires interne:
<form [formGroup]="myForm">
<div formArrayName="companies">
<div *ngFor="let comp of myForm.get('companies').controls; let i=index">
<h3>COMPANY {{i+1}}: </h3>
<div [formGroupName]="i">
<input formControlName="company" />
<button (click)="deleteCompany(i)">
Delete Company
</button>
<div formArrayName="projects">
<div *ngFor="let project of comp.get('projects').controls; let j=index">
<h4>PROJECT {{j+1}}</h4>
<div [formGroupName]="j">
<input formControlName="projectName" />
<button (click)="deleteProject(comp.controls.projects, j)">
Delete Project
</button>
</div>
</div>
<button (click)="addNewProject(comp.controls.projects)">
Add new Project
</button>
</div>
</div>
</div>
</div>
MODIFIER:
Pour définir les valeurs de votre formulaire une fois que vous avez des données, vous pouvez appeler les méthodes suivantes pour itérer vos données et définir les valeurs de votre formulaire. Dans ce cas, data
ressemble à ceci:
data = {
companies: [
{
company: "example comany",
projects: [
{
projectName: "example project",
}
]
}
]
}
Nous appelons setCompanies
pour définir les valeurs de notre forme:
setCompanies() {
let control = <FormArray>this.myForm.controls.companies;
this.data.companies.forEach(x => {
control.Push(this.fb.group({
company: x.company,
projects: this.setProjects(x) }))
})
}
setProjects(x) {
let arr = new FormArray([])
x.projects.forEach(y => {
arr.Push(this.fb.group({
projectName: y.projectName
}))
})
return arr;
}