Angular - 自定义表单组件不反映父表单组值的直接值
Angular - Custom form component not reflect value immediate to parent form group value
面临来自自定义表单组件的价值传播问题。
如果在Jobtitle中写任何东西,它会直接反映从当前到顶级表格组。
同样的事情在自动添加输入的自定义组件中不起作用。而在feeMode中写入,则只在同一个formControl中体现。
但是,那么现在,如果开始写公司名称,那么所有的值都会更新到top form group
已创建如下 stackblitz
https://stackblitz.com/edit/angular-auto-add-input?file=src/app/app.component.html
请帮我看看我错过了什么。
反应式组
professional = this.fb.group({
application: this.fb.group({
jobTitle: ['', [Validators.required]],
feeModel: this.fb.array([this.fb.control('', [Validators.required])], [Validators.required]),
companyName: ['', [Validators.required]],
})
});
自定义组件:
@Component({
selector: 'shared-auto-add-input',
templateUrl: './auto-add-input.component.html',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AutoAddInputComponent),
multi: true
}
]
})
export class AutoAddInputComponent implements OnInit, AfterViewInit {
@Input() label: string;
@Input() placeholder: string;
@Input() max: number;
@Input() formArrayName: string;
@Input() errors: ErrorModel[];
arrayControl: FormArray;
form: FormGroup;
constructor(
@Optional() @Host() @SkipSelf()
private controlContainer: ControlContainer,
private fb: FormBuilder,
) { }
ngOnInit() {
if (!this.formArrayName) {
throw new TypeError('\'formArrayName\' is required.');
}
this.form = this.fb.group({
option: this.controlContainer.control.get(this.formArrayName)
});
this.arrayControl = this.form.get('option') as FormArray;
}
ngAfterViewInit() {
}
addOption() {
this.arrayControl.push(this.fb.control('', this.controlContainer.control.get(this.formArrayName).validator));
}
removeOption(index: number) {
this.arrayControl.removeAt(index);
}
stopNew(option, i) {
return option.value === ''
|| i !== this.arrayControl.controls.length - 1
|| (this.max && this.arrayControl.controls.length === +this.max);
}
getErrors(error: FormControl) {
let result = [];
if (this.errors) {
result = this.errors.filter((message) => {
return error.hasError(message.key);
});
}
return result;
}
}
看起来您正在努力处理 HTML 文件上的数据绑定,因为您正在使用 json 过滤器绑定要在 HTML 上打印的完整对象。重新绘制 html 时似乎没有考虑更改,因为它必须比较对象内的数组。我不认为这是一个问题(取决于你想做什么)。
事实证明 angular 会进行更改检查,这取决于您如何绑定 HTML,在您的情况下是一个完整的对象,它不会深入检查它是否已更改。
值已更改但没有触发事件来重新呈现绝对父对象的值。在子组件中,您在 new form
下操作,仅引用原始 formControl 或 formarray。
this.fb({})
创建一个新表单。控件值已更改,因为引用相同但随后无法呈现新值,因为没有来自父页面一直跟踪的父表单的触发器。
这就是为什么它总是传递给子项的表单组,这样您就不会在其中创建新的表单组。这样做,就可以很好地跟踪表单组。这是对您的代码的快速修改。我使用了 formcontrol,因为它更容易,但是你可以对 formArrays 使用相同的技巧。
抱歉,我在自定义表单组件中更改值后错过了调用 updateValueAndValidity()
this.form.valueChanges
.subscribe(() => {
this.controlContainer.control.updateValueAndValidity();
});
现在,它正在工作。
面临来自自定义表单组件的价值传播问题。
如果在Jobtitle中写任何东西,它会直接反映从当前到顶级表格组。 同样的事情在自动添加输入的自定义组件中不起作用。而在feeMode中写入,则只在同一个formControl中体现。
但是,那么现在,如果开始写公司名称,那么所有的值都会更新到top form group
已创建如下 stackblitz
https://stackblitz.com/edit/angular-auto-add-input?file=src/app/app.component.html
请帮我看看我错过了什么。
反应式组
professional = this.fb.group({
application: this.fb.group({
jobTitle: ['', [Validators.required]],
feeModel: this.fb.array([this.fb.control('', [Validators.required])], [Validators.required]),
companyName: ['', [Validators.required]],
})
});
自定义组件:
@Component({
selector: 'shared-auto-add-input',
templateUrl: './auto-add-input.component.html',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AutoAddInputComponent),
multi: true
}
]
})
export class AutoAddInputComponent implements OnInit, AfterViewInit {
@Input() label: string;
@Input() placeholder: string;
@Input() max: number;
@Input() formArrayName: string;
@Input() errors: ErrorModel[];
arrayControl: FormArray;
form: FormGroup;
constructor(
@Optional() @Host() @SkipSelf()
private controlContainer: ControlContainer,
private fb: FormBuilder,
) { }
ngOnInit() {
if (!this.formArrayName) {
throw new TypeError('\'formArrayName\' is required.');
}
this.form = this.fb.group({
option: this.controlContainer.control.get(this.formArrayName)
});
this.arrayControl = this.form.get('option') as FormArray;
}
ngAfterViewInit() {
}
addOption() {
this.arrayControl.push(this.fb.control('', this.controlContainer.control.get(this.formArrayName).validator));
}
removeOption(index: number) {
this.arrayControl.removeAt(index);
}
stopNew(option, i) {
return option.value === ''
|| i !== this.arrayControl.controls.length - 1
|| (this.max && this.arrayControl.controls.length === +this.max);
}
getErrors(error: FormControl) {
let result = [];
if (this.errors) {
result = this.errors.filter((message) => {
return error.hasError(message.key);
});
}
return result;
}
}
看起来您正在努力处理 HTML 文件上的数据绑定,因为您正在使用 json 过滤器绑定要在 HTML 上打印的完整对象。重新绘制 html 时似乎没有考虑更改,因为它必须比较对象内的数组。我不认为这是一个问题(取决于你想做什么)。
事实证明 angular 会进行更改检查,这取决于您如何绑定 HTML,在您的情况下是一个完整的对象,它不会深入检查它是否已更改。
值已更改但没有触发事件来重新呈现绝对父对象的值。在子组件中,您在 new form
下操作,仅引用原始 formControl 或 formarray。
this.fb({})
创建一个新表单。控件值已更改,因为引用相同但随后无法呈现新值,因为没有来自父页面一直跟踪的父表单的触发器。
这就是为什么它总是传递给子项的表单组,这样您就不会在其中创建新的表单组。这样做,就可以很好地跟踪表单组。这是对您的代码的快速修改。我使用了 formcontrol,因为它更容易,但是你可以对 formArrays 使用相同的技巧。
抱歉,我在自定义表单组件中更改值后错过了调用 updateValueAndValidity()
this.form.valueChanges
.subscribe(() => {
this.controlContainer.control.updateValueAndValidity();
});
现在,它正在工作。