gpt4 book ai didi

angular - 如何从实现 ControlValueAccessor 的组件中获取对 FormControl 的引用?

转载 作者:太空狗 更新时间:2023-10-29 17:21:19 28 4
gpt4 key购买 nike

我创建了一个派生自 this blog post 的 Angular 组件.我有一个 react 形式,我想在表单控件上得到错误,组件本身会有一个程式化的错误消息,当控件有错误时它会呈现。但是,当我尝试将 NgControl 类注入(inject)到组件中时,我遇到了循环引用问题,那么我将如何访问控件上的错误?

这是当前的代码,它还没有完成,但它应该给出了我想要完成的事情的基本概念:

import { Component, Output, EventEmitter, Input, forwardRef } from '@angular/core';
import {
NgControl,
NG_VALUE_ACCESSOR,
ControlValueAccessor,
Validator,
AbstractControl,
FormControl,
NG_VALIDATORS
} from '@angular/forms';

@Component({
selector: 'form-field-input',
templateUrl: './form-field-input.component.html',
styleUrls: ['./form-field-input.component.less'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FormFieldInputComponent),
multi: true
}]
})
export class FormFieldInputComponent implements ControlValueAccessor {

private propagateChange = (_: any) => { };
private propagateTouch = (_: any) => { };

@Input('label') label: string;
@Input('type') type: string;
@Input('id') id: string;
@Input('formControlName') formControlName: string;
@Input('error') error: string;
@Input('classes') classes: any;

private value: string;
private data: any;

constructor() {
debugger;
}

private onChange(event) {
this.data = event.target.value;
this.propagateChange(this.data);
this.propagateTouch(this.data);
}

writeValue(obj: any): void {
this.data = obj;
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
this.propagateTouch = fn;
}
}

模板文件:

<div class="form-field-input-component">
<input id="{{id}}"
type="{{type}}"
class="form-field-input"
[value]="data"
(change)="onChange($event)"
(keyup)="onChange($event)" />
<span class="context-icon fa fa-lock"></span>
<span class="info-icon fa fa-info-circle"></span>
<!-- I will have an NGIF here to check for errors before rendering the error -->
<div class="form-error">
{{ error }}
</div>
</div>

最佳答案

我希望通过某种依赖注入(inject)或声明式的方式来做到这一点。由于我无法使用这些方法找到任何东西,因此我将分享我如何针对我的案例解决此问题。

我刚刚将 formGroup 作为输入参数添加到组件,随着 formControlName begin 传递,我能够获得对该控件的引用。

这是我的组件的最终结果

//Typescript code file for component
/// ... necessary imports
@Component({
selector: 'form-field-input',
templateUrl: './form-field-input.component.html',
styleUrls: ['./form-field-input.component.less'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FormFieldInputComponent),
multi: true
}]
})
export class FormFieldInputComponent implements ControlValueAccessor {

private propagateChange = (_: any) => { };
private propagateTouch = (_: any) => { };

@Input('label') label: string;
@Input('type') type: string;
@Input('id') id: string;
@Input('contextIconName') contextIconName: string;

//Here I take in both the parent form and the form control name
//in ngOnInit I throw if there is no parent form passed
@Input('formControlName') formControlName: string;
@Input('parentForm') parentForm: FormGroup;

@Input('classes') classes: any;
@Input('errorDefs') errorDefs: any;

private error: string;
private value: string;
private data: any;
private control: AbstractControl;

constructor() {}

ngOnInit() {
if (!this.parentForm) {
throw "Form Field input component must be a part of a form group"
}

//It ain't pretty but here we get access to the control and all of it's errors
this.control = this.parentForm.get(this.formControlName);
if (!this.control) {
throw "Form Field input component must be a part of a form group"
}
}

private setError() {
if (this.errorDefs && this.control.errors) {
var errorKeys = Object.keys(this.control.errors).filter(x => !!x);
if (errorKeys) {
var errorKey = errorKeys[0];
var error = this.errorDefs[errorKey] || null;
this.error = error;
return;
}
}
this.error = null;
}

//Now on our on change event we can propagate the events
//To the registered handlers, which should set the form field errors
//and at the end we can check the reference to the control for those errors
//so that we can display the appropriate messages
private onChange(event) {
this.data = event ? event.target.value : this.data;
this.propagateChange(this.data);
this.propagateTouch(this.data);
this.setError();
}

writeValue(obj: any): void {
this.data = obj;
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
this.propagateTouch = fn;
}
}

//HTML template file
<div class="form-field-input-component">
<input id="{{id}}"
type="{{type}}"
class="form-field-input {{class}}"
[value]="data"
(change)="onChange($event)"
(keyup)="onChange($event)"
(blur)="onChange($event)" />
<span class="context-icon fa {{contextIconName || 'fa-cog'}}"></span>
<span class="info-icon fa fa-info-circle" *ngIf="error"></span>
<div class="form-field-error" *ngIf="error">
{{ error }}
</div>
</div>

//EXAMPLE USAGE:
<form novalidate [formGroup]="myFormGroup">
<form-field-input
formControlName="firstName"
[parentForm]="myFormGroup"

<!-- example: When the Validators.required sets it's error message we can map that to a user friendly error -->
[errorDefs]="{
'required': 'this field is required'
}"
<!-- Other inputs and stuff-->
>
</form-field-input>
</form>

关于angular - 如何从实现 ControlValueAccessor 的组件中获取对 FormControl 的引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43351218/

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