提问人:Jinglemahn 提问时间:10/18/2023 最后编辑:Jinglemahn 更新时间:10/18/2023 访问量:197
如何解决 Angular 中表单控件名称的无值访问器?
How to resolve No value accessor for form control name in Angular?
问:
我正在尝试实现以下目标,我可以将组件包装在标签中,在那里我可以使用 Angular 和 StorybookJS 动态绑定到 TestField 输入,如下所示。<app-test-field>
<form>
formControlName
formGroup
但是,我遇到了以下错误:
- core.mjs:11483 错误错误:NG01203:表单控件名称没有值访问器:“name”。
- core.mjs:11483 错误错误:NG01050:formControlName 必须与父 formGroup 指令一起使用。您需要添加一个 formGroup 指令,并向其传递一个现有的 FormGroup 实例(您可以在类中创建一个)。
在 TestField.stories.js 中
这是我在 StorybookJS 中的 Angular 组件的模板。
<form [formGroup]="sampleForm">
<!-- name input -->
<app-test-field [label]="label" [formControlName]="formControlName"></app-test-field>
<!-- email input... -->
<!-- more inputs... -->
</form>
在 test-field.component.html 中
<div class="form-group">
<label for="{{ formControlName }}">{{ label }}</label>
<input
type="text"
class="form-control"
[formControlName]="formControlName"
[id]="formControlName"
/><br />
</div>
在test-field.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-test-field',
templateUrl: './test-field.component.html',
styleUrls: ['./test-field.component.css'],
})
export class TestFieldComponent {
@Input() label: string = '';
@Input() formControlName: string = '';
}
我在网上研究了大多数示例,其中输入本身被组件本身中的标签包裹起来,如下所示:<form>
<form [formGroup]="registerForm">
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" [ngClass]="inputDanger" formControlName="name"><br/>
</span>
<br/>
</div>
</form>
但是我想删除标签,以便最终目标如下,其中输入本身就是一个包装在标签中的组件,如下所示:form
<form>
<form [formGroup]="sampleForm">
<!-- name input -->
<app-test-field [label]="label" [formControlName]="formControlName"></app-test-field>
<!-- email input... -->
<!-- more inputs... -->
</form>
有人可以帮我解决这个问题吗?有什么遗漏吗?
答:
要在没有包装形式的单独组件中使用控件,您可以使用 Angular 的 NgControl
以下是该问题情况下的用法示例:
在test-field.component.ts:
ngControl 在构造函数中传递,并具有一些必需的函数
import { Component, Input, Optional, Self } from '@angular/core';
import { NgControl } from '@angular/forms';
@Component({
selector: 'app-test-field',
templateUrl: './test-field.component.html',
styleUrls: ['./test-field.component.scss'],
})
export class TestFieldComponent {
@Input() label: string = '';
onChange: any = () => {};
onTouch: any = () => {};
constructor(@Optional() @Self() public ngControl: NgControl) {
if (this.ngControl != null) {
this.ngControl.valueAccessor = this;
}
}
ngOnInit(): void {}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouch = fn;
}
writeValue(value: any): void {}
}
现在,在 test-field.component.html 中使用 ngControl:
<div class="form-group">
<label for="{{ ngControl?.name }}">{{ label }}</label>
<input
type="text"
class="form-control"
[formControl]="ngControl?.control"
[id]="ngControl?.name"
/><br />
</div>
在TestField.stories.js中,您只能删除“formControlName”输入,因为不再需要它:
<form [formGroup]="sampleForm">
<!-- name input -->
<app-test-field [label]="label"></app-test-field>
<!-- email input... -->
<!-- more inputs... -->
</form>
评论
Type 'AbstractControl<any, any> | null | undefined' is not assignable to type 'FormControl<any>'
为您的组件创建一个:ControlValueAccessor
app-test-field
import { Component, Input, forwardRef, NG_VALUE_ACCESSOR } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'app-test-field',
templateUrl: './test-field.component.html',
styleUrls: ['./test-field.component.css'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TestFieldComponent),
multi: true,
},
],
})
export class TestFieldComponent implements ControlValueAccessor {
@Input() label: string = '';
@Input() formControlName: string = '';
// Implement ControlValueAccessor methods
onChange: any = () => {};
onTouched: any = () => {};
writeValue(value: any) {}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: any) {
this.onTouched = fn;
}
}
更新 ur 以使用指令:test-field.component.html
ngModel
<div class="form-group">
<label for="{{ formControlName }}">{{ label }}</label>
<input
type="text"
class="form-control"
[id]="formControlName"
[ngModel]="value"
(ngModelChange)="onChange($event)"
/><br />
</div>
现在,在父组件中,当您使用 时,它应该按预期工作:app-test-field
<form [formGroup]="sampleForm">
<app-test-field [label]="label" [formControlName]="formControlName"></app-test-field>
</form>
评论