gpt4 book ai didi

angular - 如何将 NgControl 状态传递给 Angular 中的子组件,实现 ControlValueAccessor?

转载 作者:行者123 更新时间:2023-12-03 20:27:48 24 4
gpt4 key购买 nike

假如

{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TestingComponent),
multi: true
}

注入(inject) NgControl
constructor(@Self() @Optional() public control: NgControl) {
this.control && (this.control.valueAccessor = this);
}

然而这里缺少什么?

enter image description here

尽管@Eliseo 的回答非常具有解释性,但还有一个补充......如果您想同时使用外部验证器和内部验证器,则必须相应地设置父 NgControl 验证器。此外,如果你想使用验证,你需要使用 ngDoCheck 生命周期钩子(Hook)来处理 NgControl 触摸状态,因为我下面是 最终工作解决方案
@Component({
selector: 'app-testing',
templateUrl: 'testing.component.html'
})
export class TestingComponent implements ControlValueAccessor, DoCheck, AfterViewInit {
@Input()
public required: boolean;

@ViewChild('input', { read: NgControl })
private inputNgModel: NgModel;

public value: number;
public ngControlTouched: boolean;

constructor(@Optional() @Self() public ngControl: NgControl) {
if (this.ngControl != null) this.ngControl.valueAccessor = this;
}

ngDoCheck() {
if (this.ngControlTouched !== this.ngControl.touched) {
this.ngControlTouched = this.ngControl.touched;
}
}

ngAfterViewInit() {
// Setting ngModel validators to parent NgControl
this.ngControl.control.setValidators(this.inputNgModel.validator);
}

/**
* ControlValueAccessor Implementation
* Methods below
*/
writeValue(value: number): void {
this.value = value;
this.onChange(this.value);
}

onChange: (_: any) => void = (_: any) => {};

onTouched: () => void = () => {};

registerOnChange(fn: any): void {
this.onChange = fn;
}

registerOnTouched(fn: any): void {
this.onTouched = fn;
}
}

// Template
<input
#input="ngModel"
type="text"
class="form-control"
[class.is-invalid]="input.invalid && (input.dirty || input.touched || ngControlTouched)"
[(ngModel)]="value"
(ngModelChange)="onChange(value)"
(blur)="onTouched()"
[required]="required"
/>

// Usage
<app-testing [(ngModel)]="propertyDetails.whatThreeWords" name="testing" required></app-testing>

最佳答案

你有两个选择:

注入(inject) NgControl,为此您需要删除提供程序并以方式制作构造函数

constructor(public control:NgControl){
if (this.control != null) {
this.control.valueAccessor = this;
}
}

然后你可以像这样装饰你的输入
<input [ngClass]="{'ng-invalid':control.invalid,'ng-valid':control.valid...}">

或者将 customFormControl 的类复制到输入中。

你的输入就像
<input [ngClass]="class">

如果在自定义表单控件的构造函数中导入 ElementRef
constructor(private el:ElementRef){}

并创建一个函数“copyClass”
  copyClass()
{
setTimeout(()=>{
this.class=this.elementRef.nativeElement.getAttribute('class')
})
}

您可以在 writeValue、Change 和 OnTouched 中调用此函数。

我能想象的最简单的例子是 this stackblitz

注意:如果您的问题是您在组件中使用了 Material Angular ,则技术正在使用 customErrorMatcher,请查看 official docs并且,如果您想在 stackoverflow 中回答这个问题

更新 另一种方法是为输入设置相同的验证器。为此,我们使用 viewChild 来获取输入,并且在 ngAfterViewInit 中等于验证器
 @ViewChild('input',{static:false,read:NgControl}) input

ngAfterViewInit()
{
if (this.control != null) {
this.input.control.setValidators(this.control.control.validator)
}

}

another stackblitz

最后更新如果我们想在控件内部有一个自定义错误,我们可以使用函数 validate 来获取控件,而不是在构造函数中注入(inject)。组件变得像
@Component({
...
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomFormControlComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => CustomFormControlComponent),
multi: true,
}]

})
export class CustomFormControlComponent implements ControlValueAccessor,
Validator, AfterViewInit {
...
control:any
@ViewChild('input', { static: false, read: NgControl }) input
constructor() {
}
ngAfterViewInit() {
this.validate(null)
}
validate(control: AbstractControl): ValidationErrors | null{
if (!this.control)
this.control=control;

if (this.control && this.input)
this.input.control.setValidators(this.control.validator)

if (control.value=="qqq")
return {error:"Inner error:The value is 1"}

return null
}

一个新的 stackblitz

关于angular - 如何将 NgControl 状态传递给 Angular 中的子组件,实现 ControlValueAccessor?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57186593/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com