gpt4 book ai didi

angular - 通过查询组件的模板获取 FormControl 实例

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

我有一个自定义 FormFieldComponent封装表单字段的 HTML 和错误显示逻辑:

@Component({
selector: 'field',
template: `
<div class="form-group">
<label class="control-label">{{label}}</label>
<ng-content></ng-content> <!-- Will display the field -->
<!-- Here, put error display logic -->
</div>
`
})
export class FormFieldComponent {
@Input() label: string; // Field label
@Input() theControl: FormControl; // Current form control, required to display errors
}

FormFieldComponent ,我需要一个 FormControl 的实例来显示错误。

我的表格看起来像这样:

<form [formGroup]="myForm">
...
<field label="Title" [theControl]="myForm.get('title')">
<input type="text" formControlName="title">
</field>
...
</form>

但我对上面的代码并不完全满意。如您所见,我在两个位置指定字段的键:在 [theControl] 中。输入属性和 formControlName指令。

如果我能这样写代码会更简洁:

<field label="Title">
<input type="text" formControlName="title">
</field>

注意 [theControl]输入属性消失了。 FieldComponent应该能够获取它包含的 FormControl 实例,但是如何获取呢?

我试过使用 @ContentChildren为 FormControl 指令查询组件模板的装饰器,但它不起作用:

export class FormFieldComponent {
@ContentChildren(FormControlDirective) theControl: any;
}

另一种选择是将字段的键作为输入传递给 FormFieldComponent然后让组件使用该键来:

  • 以编程方式应用 formControlName指令包含的字段。
  • 获取其父项<form> ,访问相应的 FormGroup 实例,并从中提取 FormControl 实例。

最佳答案

简答:你不能

你就是做不到。 (好吧,也许你可以,但这会很麻烦!)

长答案:你不能,但是......

FormControl 不可注入(inject)。指令是可注入(inject)的,但是,您必须处理 formControlNamengModelformControl 等,它们不能从包装组件访问,但它的子组件...

对于您的情况,您可以尝试使用 @ContentChildren(FormControlName) theControl: any;,因为您的代码中没有隐含 FormControlDirective,但无论如何您都无法访问 FormControl(属性 _control 是内部的,所以它会被黑客攻击)...

因此,您应该坚持从处理 FormGroup 的组件管理错误。

但是 如果您想显示自定义输入(不会按原样显示错误消息但能够显示此输入处于错误状态(宿主元素将获得 ng-validng-invalid 类,所以这只是样式问题),您可以通过实现 ControlValueAccessor 来做到这一点。

A bridge between a control and a native element.

A ControlValueAccessor abstracts the operations of writing a new value to a DOM element representing an input control.

这意味着实现此接口(interface)的指令/组件可以与 ngModelformControl 等一起使用...

例如:<my-component [(ngModel)]="foo"></my-component>

这不是您问题的精确再现,但此实现为我解决了同类问题:

export const INPUT_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => InputComponent),
multi: true
};

@Component({
selector: "field",
template: `<!--put anything you want in your template-->
<label>{{label}}</label>
<input #input (input)="onChange($event.target.value)" (blur)="onTouched()" type="text">`,
styles: [],
providers: [INPUT_VALUE_ACCESSOR]
})
export class InputComponent implements ControlValueAccessor {
@ViewChild("input")
input: ElementRef;
@Input()
label:string;
onChange = (_: any) => { };
onTouched = () => { };

constructor(private _renderer: Renderer) { }

writeValue(value: any): void {
const normalizedValue = value == null ? "" : value;
this._renderer.setElementProperty(this.input.nativeElement, "value", normalizedValue);
}

registerOnChange(fn: (_: any) => void): void {
this.onChange = fn;
}
registerOnTouched(fn: () => void): void { this.onTouched = fn; }

setDisabledState(isDisabled: boolean): void {
this._renderer.setElementProperty(this.input.nativeElement, "disabled", isDisabled);
}
}

那么你可以:

<field label="Title" formControlName="title"></field>

关于angular - 通过查询组件的模板获取 FormControl 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40674834/

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