我在我的应用程序中使用了反应式表单,并使用formcontrolName绑定到html。但是现在,我不需要在formbuilder中声明属性,而是需要调用一个模型,并将该模型分配给formbuilder,并在html中使用它.我已经通过许多链接,但没有找到任何地方如何根据我的要求工作。
HTML。
<div class="tab-pane fade h-100 active show" id="tab-user_1" role="tabpanel" aria-labelledby="user_1"
*ngIf="userInfoForm" [formGroup]="userInfoForm">
<div class="row">
<div class="col-6">
<div class="form-group">
<label for="">Agent Code <span class="text-danger">*</span></label>
<input type="text" formControlName="agentCode" class="form-control">
</div>
</div>
</div>
TS:
this.userInfoForm = this.FB.group({
Id: 0,
agentCode: this.agentCode,
userName: [''],
firstName: [''],
middleName: '',
lastName: [''],
department: [''],
});
this.userInfoForm.controls['agentCode'].disable();
model.ts:
export class UserFormDetails {
Id: number;
agentCode: number;
userName: string;
firstName: string;
middleName: string;
lastName: string;
department: string;
}
根据评论,听起来你想要一个基于模型的动态表单...没有 "开箱即用 "的解决方案。你可以写你自己的表单模型。
interface MyFormModelField {
initial?: {
value: any,
disabled: boolean
},
controlOptions?: AbstractControlOptions
// anything you find useful really?
}
export type MyFormModel<T> = Record<keyof T, MyFormModelField>
然后像这样实现它:
const USER_FORM_MODEL: MyFormModel<UserFormDetails> = {
Id: { },
agentCode: {
initial: {
value: '',
disabled: true
},
controlOptions: {
validators: Validators.required
}
},
userName: { },
firstName: { },
middleName: { },
lastName: { },
department: { },
}
然后你可以写一个服务来生成基于表单模型的表单组... ...
@Injectable({providedIn: 'root'})
export class MyFormBuilder {
constructor(private: fb) { }
buildForm<T>(formModel: MyFormModel<T>) {
const fg = Object.keys(formModel).reduce((grp, k) => {
const fld = formModel[k];
return Object.assign(grp, {
[k]: [fld.initial || '', fld.controlOptions]
})
}, {});
return this.fb.group(fg);
}
}
现在,只要你对 UserFormDetails
接口,typecript会向你喊话,让你用字段信息更新相应的表单模型......虽然更新不会从模型更新中 "自动 "流出,但你至少在表单中拥有一些类型安全。我个人在这里就不说了。
接下来的这个部分并不完美,我也不喜欢它,但是如果你真的希望下一步能从类定义中或多或少地实现自动更新,你可以写一个函数从类中建立一个默认的表单模型,就像这样。
function buildDefaultFormModel<T>(model: new () => T) {
return Object.keys(new model()).reduce((form, k) => {
return Object.assign(form, {[k]: {}})
}, {} as MyFormModel<T>)
}
这需要2件事情,1,你的类必须为每个字段指定一个默认值,没有默认值的字段不会被包含。(这就引入了对字段有默认值的隐性依赖,这也是我不喜欢这种方法的原因,不过,如果你写了一个没有默认值或构造函数赋值的属性的类,你可以配置ts来吼你)。
class UserFormDetails {
Id: number = 0;
agentCode: number = 0;
userName: string = '';
firstName: string = '';
middleName: string = '';
lastName: string = '';
department: string = '';
}
2,对象构造函数必须不接受任何参数,但如果你试图在这种情况下滥用它,TS会对你大喊大叫。
函数可以这样使用。
const USER_FORM_MODEL: MyFormModel<UserFormDetails> = {
...buildDefaultFormModel(UserFormDetails),
...{
agentCode: {
initial: {
value: '',
disabled: true
},
controlOptions: {
validators: Validators.required
}
},
}
}
这样你就可以使用默认字段, 也可以为特定字段提供覆盖。
最后,你也可以利用这个表单模型来建立一个模板,但这是一个更大的任务。
这是一个全部实现的突击项目(我还提前清理了控制器的代码)。https:/stackblitz.comeditgithub-ck3u8u-qtnasc?file=src%2Fapp%2Fuser-table%2Fuser-table.validators.ts。
你必须在FormGroup表单控件中使用patchValue来绑定你的模型。
this.userInfoForm = this.FB.group({
Id: 0,
agentCode: this.agentCode,
userName: [''],
firstName: [''],
middleName: '',
lastName: [''],
department: [''],
});
这是正确的,当你得到UserFormDetails对象时,你必须把它传递给表单,你必须做.PatchValue。
this.userInfoForm.patchValue({
'Id': UserFormDetails.id
...
})
而当你必须将表单控件的值传递给对象时。
this.UserFormDetail.id = this.userInfoForm.get('Id').value
等等...
我想这可能是你正在寻找的解决方案。
private initUserForm() {
// mapping the object into the form model
this.userInfoForm = this.FB.group({ ...this.userDetails });
// if you want to add validators or disable buttons...
this.userInfoForm.controls.agentCode.setValidators(Validators.required); // adding validations
this.userInfoForm.controls.agentCode.disable();
// console.log(this.userInfoForm.controls);
}
这种方式满足了你对 "绑定 "的需求,这不是一个真正的绑定,因为框架不允许这样的事情,但它允许你从对象模型值映射到创建反应式表单模型。
请看在添加一个extraField后,表单如何拾取该控件及其值。