问题描述
具有使用内部 FormGroup
来实现 ControlValueAccessor
的组件,以维护自定义表单控件的状态.如果禁用了属于 FormGroup
的一部分的任何字段,则以父级形式调用 .getRawValue()
方法时,该字段将不可见.
Having a component that implements ControlValueAccessor
, with internal FormGroup
to maintain the state of custom form control. When any field, that's part of that FormGroup
is disabled, the field isn't visible when calling .getRawValue()
method in parent form .
根据规范, .getRawValue()
应该返回原始对象,包括禁用的字段.
By specification, .getRawValue()
should return the raw object, including disabled fields.
我已经检查了 .getRawValue()
的代码,这就是我发现的内容:
I've checked the code of .getRawValue()
and here's what I found:
getRawValue(): any {
return this._reduceChildren(
{}, (acc: {[k: string]: AbstractControl}, control: AbstractControl, name: string) => {
acc[name] = control instanceof FormControl ? control.value : (<any>control).getRawValue();
return acc;
});
}
因此,基本上,当表单控件是 FormControl
的实例时(使用自定义表单控件时是这种情况,对吗?),它将检索 .value
而不是 .getRawValue()
,这就是为什么在最终对象中不包含禁用嵌套形式的控件的原因.
So, basically, when form control is instance of FormControl
(that's the case when using custom form controls, correct?), it retrieves .value
instead of .getRawValue()
and that's why the disabled controls of nested form are not included in the final object.
复制步骤:
1)在用户界面中显示的三个自定义表单控件中的任意一个上,单击禁用年份"按钮.
1) Click on "Disable year" button on any of three custom form controls displayed in the UI.
2)检查下面的输出=> .getRawValue()
和 .value
响应是否相同.
2) Examine the output below => .getRawValue()
and .value
responses are identical.
您知道我该如何克服吗?我也在寻找一种在父窗体中检索禁用控件的方法.
Do you have any idea how I can overcome this? I'm looking for a way to retrieve the disabled controls as well in the parent form.
推荐答案
Kav,在您拥有的自定义表单控件中
Kav, in your custom form control you has
registerOnChange(fn: (v: any) => void) {
this.formGroup.valueChanges.subscribe(fn);
}
因此,您的组件返回formGroup的值".由于控件被禁用,该值不返回该字段.您可以更改customControl以返回formGroup的rawValue,为此,您需要创建一个onChangeFunction,并在ngOnInit中订阅更改并发送rawValues.在我们订阅时,最好使用takeWhile和变量取消订阅
so, your component return the "value" of formGroup. As a control is disabled, the value not return this field. You can change your customControl to return the rawValue of the formGroup, for this you need create a onChangeFunction, and in a ngOnInit subscribe to changes and send the rawValues. As we subscribe it's good unsubscribe using a takeWhile and a variable
export class DetailsFields implements ControlValueAccessor,OnInit,OnDestroy {
...
onChange: (v:any) => void = () => {}; //<--define a function
isAlive:boolean=true; //<--use to unsubscribe, see below
registerOnChange(fn: (v: any) => void) {
this.onChange = fn; //<--equal to function
}
//In ngOnInit
ngOnInit()
{
this.formGroup.valueChanges.pipe(takeWhile(()=>this.isAlive))
.subscribe(v=>{
//return this.formGroup.getRawValue()
this.onChange(this.formGroup.getRawValue())
})
}
//In ngOnDestroy
ngOnDestroy() { //make isAlive=False to unsubscribe
this.isAlive=false;
}
但是在这种情况下,您收到的年份始终处于启用状态
But in this case, you received the year always is enabled or not
还有另一种方法,即没有自定义表单控件,而只是用于管理品牌,年份和颜色的组件.为此,首先是更改您的应用程序组件,并使用formArray与其他表单一样创建该表单.
There're another aproach, that is not have a custom form control, just a component to manage the make,year and color. For this, the first is change your app-component and create the form like another form with a formArray.
<div id="cars" [formGroup]="form">
<div formArrayName="cars">
<div *ngFor="let car of form.get('cars').controls; let i = index;"
[formGroupName]="i">
<app-details-fields [formGroup]="form.get('cars').at(i)" ></app-details-fields>
</div>
</div>
</div>
请参见,在formArray中,我们遍历form.get('cars').controls,我们需要放置一个[formGroupName] ="i".在组件中,只需将输入作为[formGroup] form.get('cars').at(i)
See that in a formArray we iterate over form.get('cars').controls and we need put a [formGroupName]="i". In the component simply pass as input [formGroup] form.get('cars').at(i)
当然,您需要更改函数"createCars"以返回formGroup.不是返回对象类型{make:..,color:..,year}
Of course, you need change your function "createCars" to return a formGroup. not a formControl that return an object type {make:..,color:..,year}
createCar(car: any) { //return a formGroup,not a formControl
return this.builder.group({
make: car.make,
color: car.color,
year: car.year
});
}
好吧,详细信息字段变得更容易了:
Well, the details-fields becomes easer:
details-fields.component.ts
details-fields.component.ts
@Component({
selector: 'app-details-fields',
templateUrl: './details-fields.component.html',
styleUrls: ['./details-fields.component.css'] ,
})
export class DetailsFields {
@Input() formGroup:FormGroup
disableYear() {
this.formGroup.get('year').disable();
}
enableYear() {
this.formGroup.get('year').enable();
}
}
details-fields.component.html
details-fields.component.html
<div [formGroup]="formGroup">
<div class="car-wrap">
<div>
<p class="title">This car is a {{formGroup.get('make').value}}</p>
<div>
<input type="text" formControlName="make">
<input type="number" formControlName="year">
<input type="text" formControlName="color">
</div>
<div>
<button style="margin-top: 3px;" (click)="enableYear()">Enable year</button>
<button style="margin-top: 3px;" (click)="disableYear()">Disable year</button>
</div>
</div>
</div>
</div>
这篇关于FormGroup中禁用的控件(窗体自定义窗体控件的一部分)被父项中的.getRawValue()排除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!