Angular11 如何使用子组件从基础组件扩展表单
Angular 11 how to extend a Form from a base component using a child component
我的应用有很多费用。所有费用都具有相同的属性,除了少数几个。假设我有这个结构:
// Base Fee
interface IFee {
id: string;
name: string;
price: string;
date: string;
}
interface IWebFee extends IFee {
url: string;
links: number;
}
interface IBookFee extends IFee {
pageCount: number;
bookTitle: string;
}
假设我想创建一个表单来编辑 BookFee。内容投影不会工作,因为不会有任何上下文。所以我尝试创建一个嵌入式视图......但我仍然无法访问父 FormGroup 以将控件附加到它。这是我所拥有的(由于我无法从 BaseFeeFormComponent 访问 FormGroup,因此会因缺少控制而引发错误):
基本费用-form.component.ts
@Component({
selector: 'app-base-fee-form',
...
providers: [
{
provide: ControlContainer,
useFactory: (comp: BaseFeeFormComponent) => comp.ngForm,
deps: [BaseFeeFormComponent],
},
],
})
export class BaseFeeFormComponent implements AfterContentInit {
@ContentChild('feeChild') templateChild: TemplateRef<any>;
@ViewChild('mountRef', { read: ViewContainerRef }) vcRef: ViewContainerRef;
@ViewChild('ngForm') ngForm: FormGroupDirective;
form: FormGroup;
constructor(protected _fb: FormBuilder) {
this.form = this._fb.group({
name: [],
price: [],
date: [],
});
}
ngAfterContentInit() {
setTimeout(() => this.vc.createEmbeddedView(this.templateChild));
}
}
基本费用-form.component.html
<form [formGroup]="form" #ngForm="ngForm">
<div class="control-group">
<span>Name: </span>
<input type="text" formControlName="name" />
</div>
<div class="control-group">
<span>Price: </span>
<input type="text" formControlName="price" />
</div>
<div class="control-group">
<span>Date: </span>
<input type="date" formControlName="date" />
</div>
<div #mountRef></div>
</form>
书费-form.component.ts
@Component({
selector: 'app-book-fee-form',
templateUrl: './book-fee-form.component.html',
styleUrls: ['./book-fee-form.component.css'],
encapsulation: ViewEncapsulation.None,
})
export class BookFeeFormComponent {
constructor(
// private _formDirective: FormGroupDirective,
private _fb: FormBuilder
) {
// this._formDirective.form.addControl('pageCount', this._fb.control(0));
// this._formDirective.form.addControl('bookTitle', this._fb.control(null));
}
ngOnInit() {}
}
书费-form.component.html
<app-base-fee-form>
<ng-template #feeChild>
<div class="control-group">
<span>Page Count: </span>
<input type="text" formControlName="pageCount" />
</div>
<div class="control-group">
<span>Book Title: </span>
<input type="text" formControlName="bookTitle" />
</div>
</ng-template>
</app-base-fee-form>
如何访问父 NgForm 以将所需的控件附加到现有的 FormGroup?相反,有没有更简单的方法来做到这一点?我试图避免为共享几乎相同模板和功能的每个表单创建组件。
我创建了一个 Stackblitz 来展示我的问题:StackBlitz
一种解决方案是将控件表示为对象,并动态生成它们
export type control = {
label: string;
type: string;
formControlName: string;
};
base-fee-form.component.html
<form [formGroup]="form" #ngForm="ngForm">
<ng-container *ngFor="let control of controls">
<div class="control-group">
<span>{{ control.label }}: </span>
<input
type="{{ control.type }}"
formControlName="{{ control.formControlName }}"
/>
</div>
</ng-container>
</form>
在基本组件中定义常用控件
export class BaseFeeFormComponent {
controls: control[] = [
{ label: 'Name', type: 'text', formControlName: 'name' },
{ label: 'Price', type: 'text', formControlName: 'price' },
{ label: 'Date', type: 'date', formControlName: 'date' },
];
form: FormGroup;
constructor(protected _fb: FormBuilder) {
this.form = this._fb.group({
name: [],
price: [],
date: [null],
});
}
}
然后extend
添加新控件的基础组件
export class BookFeeFormComponent extends BaseFeeFormComponent {
constructor(protected _fb: FormBuilder) {
super(_fb);
this.controls = this.controls.concat([
{ label: 'Page Count', type: 'text', formControlName: 'pageCount' },
{ label: 'Book Title', type: 'text', formControlName: 'bookTitle' },
]);
this.form = this._fb.group({
...this.form.controls,
pageCount: [],
bookTitle: [],
});
}
}
您可以为每个组件自定义 html,或者将子组件指向基础 html
@Component({
selector: 'app-book-fee-form',
templateUrl: '../base-fee-form/base-fee-form.component.html',
...
Stackblitz:https://stackblitz.com/edit/angular-ivy-rwm5jw?file=src/app/book-fee-form/book-fee-form.component.ts
我的应用有很多费用。所有费用都具有相同的属性,除了少数几个。假设我有这个结构:
// Base Fee
interface IFee {
id: string;
name: string;
price: string;
date: string;
}
interface IWebFee extends IFee {
url: string;
links: number;
}
interface IBookFee extends IFee {
pageCount: number;
bookTitle: string;
}
假设我想创建一个表单来编辑 BookFee。内容投影不会工作,因为不会有任何上下文。所以我尝试创建一个嵌入式视图......但我仍然无法访问父 FormGroup 以将控件附加到它。这是我所拥有的(由于我无法从 BaseFeeFormComponent 访问 FormGroup,因此会因缺少控制而引发错误):
基本费用-form.component.ts
@Component({
selector: 'app-base-fee-form',
...
providers: [
{
provide: ControlContainer,
useFactory: (comp: BaseFeeFormComponent) => comp.ngForm,
deps: [BaseFeeFormComponent],
},
],
})
export class BaseFeeFormComponent implements AfterContentInit {
@ContentChild('feeChild') templateChild: TemplateRef<any>;
@ViewChild('mountRef', { read: ViewContainerRef }) vcRef: ViewContainerRef;
@ViewChild('ngForm') ngForm: FormGroupDirective;
form: FormGroup;
constructor(protected _fb: FormBuilder) {
this.form = this._fb.group({
name: [],
price: [],
date: [],
});
}
ngAfterContentInit() {
setTimeout(() => this.vc.createEmbeddedView(this.templateChild));
}
}
基本费用-form.component.html
<form [formGroup]="form" #ngForm="ngForm">
<div class="control-group">
<span>Name: </span>
<input type="text" formControlName="name" />
</div>
<div class="control-group">
<span>Price: </span>
<input type="text" formControlName="price" />
</div>
<div class="control-group">
<span>Date: </span>
<input type="date" formControlName="date" />
</div>
<div #mountRef></div>
</form>
书费-form.component.ts
@Component({
selector: 'app-book-fee-form',
templateUrl: './book-fee-form.component.html',
styleUrls: ['./book-fee-form.component.css'],
encapsulation: ViewEncapsulation.None,
})
export class BookFeeFormComponent {
constructor(
// private _formDirective: FormGroupDirective,
private _fb: FormBuilder
) {
// this._formDirective.form.addControl('pageCount', this._fb.control(0));
// this._formDirective.form.addControl('bookTitle', this._fb.control(null));
}
ngOnInit() {}
}
书费-form.component.html
<app-base-fee-form>
<ng-template #feeChild>
<div class="control-group">
<span>Page Count: </span>
<input type="text" formControlName="pageCount" />
</div>
<div class="control-group">
<span>Book Title: </span>
<input type="text" formControlName="bookTitle" />
</div>
</ng-template>
</app-base-fee-form>
如何访问父 NgForm 以将所需的控件附加到现有的 FormGroup?相反,有没有更简单的方法来做到这一点?我试图避免为共享几乎相同模板和功能的每个表单创建组件。
我创建了一个 Stackblitz 来展示我的问题:StackBlitz
一种解决方案是将控件表示为对象,并动态生成它们
export type control = {
label: string;
type: string;
formControlName: string;
};
base-fee-form.component.html
<form [formGroup]="form" #ngForm="ngForm">
<ng-container *ngFor="let control of controls">
<div class="control-group">
<span>{{ control.label }}: </span>
<input
type="{{ control.type }}"
formControlName="{{ control.formControlName }}"
/>
</div>
</ng-container>
</form>
在基本组件中定义常用控件
export class BaseFeeFormComponent {
controls: control[] = [
{ label: 'Name', type: 'text', formControlName: 'name' },
{ label: 'Price', type: 'text', formControlName: 'price' },
{ label: 'Date', type: 'date', formControlName: 'date' },
];
form: FormGroup;
constructor(protected _fb: FormBuilder) {
this.form = this._fb.group({
name: [],
price: [],
date: [null],
});
}
}
然后extend
添加新控件的基础组件
export class BookFeeFormComponent extends BaseFeeFormComponent {
constructor(protected _fb: FormBuilder) {
super(_fb);
this.controls = this.controls.concat([
{ label: 'Page Count', type: 'text', formControlName: 'pageCount' },
{ label: 'Book Title', type: 'text', formControlName: 'bookTitle' },
]);
this.form = this._fb.group({
...this.form.controls,
pageCount: [],
bookTitle: [],
});
}
}
您可以为每个组件自定义 html,或者将子组件指向基础 html
@Component({
selector: 'app-book-fee-form',
templateUrl: '../base-fee-form/base-fee-form.component.html',
...
Stackblitz:https://stackblitz.com/edit/angular-ivy-rwm5jw?file=src/app/book-fee-form/book-fee-form.component.ts