- 父组件 my-form.component.html
<div class="my-form" [formGroup]="form">
<div>
<label class="form-label">comsumer:</label>
<input class="form-control" type="text" formControlName="comsumer">
</div>
<div>
<h3>Books</h3>
<app-books formControlName="books"></app-books>
</div>
</div>
<div>
{{form.getRawValue() | json}}
</div>
my-form.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
@Component({
selector: 'app-my-form',
templateUrl: './my-form.component.html',
styleUrls: ['./my-form.component.css']
})
export class MyFormComponent implements OnInit {
form!: FormGroup;
mockData = {
comsumer: 'Zoey',
books: [
{
bookName: 'Little Prices',
bookPrice: '12.0',
bookAuthor: 'Tom'
},
{
bookName: 'Snow White',
bookPrice: '10.0',
bookAuthor: 'Jenney'
}
]
}
ngOnInit(): void {
this.form = new FormGroup({
comsumer: new FormControl(),
books: new FormControl()
});
this.form.patchValue(this.mockData);
this.form.get('books')?.valueChanges.subscribe(value => {
console.log('books changed:', value)
})
}
}
- 子组件实现ControlValueAccessor并且本身维护一个FormArray books.component.html
<div class="mb-3 d-flex justify-content-end">
<button type="button" class="btn btn-primary" (click)="addNew()">Add Book</button>
</div>
<div class="d-flex" *ngIf="booksArray">
<ng-container *ngFor="let group of bookFormArrayControls; let i = index;">
<div class="card me-2" style="width: 18rem;" [formGroup]="group">
<ul class="list-group list-group-flush">
<li class="list-group-item">
<label class="form-label">Book Name:</label>
<input class="form-control" formControlName="bookName" />
</li>
<li class="list-group-item">
<label class="form-label">Book Price:</label>
<input class="form-control" formControlName="bookPrice" />
</li>
<li class="list-group-item">
<label class="form-label">Book Author:</label>
<input class="form-control" formControlName="bookAuthor" />
</li>
</ul>
<div class="card-body">
<button class="btn btn-primary" (click)="deleteBook(i)">Delete</button>
</div>
</div>
</ng-container>
</div>
books.component.ts
import { Component } from '@angular/core';
import { ControlValueAccessor, FormArray, FormControl, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'app-books',
templateUrl: './books.component.html',
styleUrls: ['./books.component.css'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: BooksComponent,
multi: true
}
]
})
export class BooksComponent implements ControlValueAccessor {
booksArray!: FormArray;
disabled: boolean = false;
onChange!: (val: any) => void;
onTouch!: () => void;
get bookFormArrayControls() {
return this.booksArray.controls as FormGroup[];
}
writeValue(value: any[]): void {
if (!value?.length) return;
const arr = value.map(x => {
return new FormGroup({
bookName: new FormControl(x.bookName),
bookPrice: new FormControl(x.bookPrice),
bookAuthor: new FormControl(x.bookAuthor)
})
});
this.booksArray = new FormArray(arr);
this.booksArray?.valueChanges.subscribe((books: any) => this.onChange(books))
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouch = fn;
}
setDisabledState?(isDisabled: boolean): void {
this.disabled = isDisabled;
}
addNew() {
const newBook = new FormGroup({
bookName: new FormControl(''),
bookPrice: new FormControl(''),
bookAuthor: new FormControl('')
})
this.booksArray.push(newBook)
}
deleteBook(index: number) {
this.booksArray.removeAt(index)
}
}
- 页面