访问自定义 Angular 组件中的 FormControl



我正在创建一个自定义的角度组件,当我的 FormControl(反应式表单(无效时,它会显示一个错误的工具提示。 但是我不知道如何访问自定义组件中的 FormControl 以检查它是否被标记为有效。

我想完成什么

<div [formGroup]="form">
<input formControlName="name" type="text" />
<custom-validation-message formControlName="name">My special error message!</custom-validation-message>
</div>

已经遇到的东西

错误

错误:名称为"调查类型"的表单控件没有值访问器

通过使用NG_VALUE_ACCESSOR实现 ControlValueAccessor 来解决此问题,即使我不想更改该值。我还添加了一个注射器来访问NgControl。

import { Component, OnInit, Injector } from '@angular/core';
import { NgControl, ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'custom-validation-message',
templateUrl: './validation-message.component.html',
providers: [{
provide: NG_VALUE_ACCESSOR, multi: true, useExisting: ValidationMessageComponent
}]
})
export class ValidationMessageComponent implements ControlValueAccessor, OnInit {
public formControl: any;
constructor(private injector: Injector) {
super();
}
public ngOnInit(): void {
const model = this.injector.get(NgControl);
this.formControl = model.control;
}
public writeValue(obj: any): void {
}
public registerOnChange(fn: any): void {
}
public registerOnTouched(fn: any): void {
}
public setDisabledState?(isDisabled: boolean): void {
}
}

当前问题模型控件未定义。在检查模型后,我发现模型和空模型一样好,只有_parent是我表单的完整表示。model._parent.控件确实包含我的窗体的所有控件。但我仍然不知道当前的控制。

正如我得到你的观点,你只想为显示表单控件验证消息制作一个 componnet 另一个答案 explane 为什么 ControlValueAccessor 不是这里的情况,你只想将控制表单引用传递给组件然后检查验证状态,托马斯施耐特的答案是正确的为什么,但我面临这种情况,很难通过 get 方法保持重新France,有时我们在 sub组和表单数组,所以我的想法是将表单控件的名称作为字符串传递,然后获取控件引用。

自定义验证消息组件

@Component({
selector: "custom-validation-message",
templateUrl: "./custom-validation-message.component.html",
styleUrls: ["./custom-validation-message.component.css"]
})
export class CustomValidationMessageComponent {
@Input()
public controlName: string;
constructor(@Optional() private controlContainer: ControlContainer) {} 
get form(): FormGroup {
return this.controlContainer.control as FormGroup;
}
get control(): FormControl {
return this.form.get(this.controlName) as FormControl;
}
}

模板

<ng-container *ngIf="control && control?.invalid && control?.touched">
<ul>
<li *ngIf="control.hasError('required')">
this is required field
</li>
<li *ngIf="control.hasError('pattern')">
pattern is invalid 
</li>
<li *ngIf="control.hasError('maxlength')">
the length is over the max limit
</li>
<!-- <li *ngFor="let err of control.errors | keyvalue">
{{err.key}}
</li> -->
</ul>
</ng-container>

你可以这样使用它

<form [formGroup]="form">
<label>
First Name <input type="text" formControlName="firstName" />
<div>
<custom-validation-message controlName="firstName"></custom-validation-message>
</div>
</label>
...
</form>

演示 🚀🚀

您可以查看由JB Nizet创建的这个角度库ngx-valdemort,它完美👌地解决了这个问题。

如果我理解正确,<custom-validation-message>应该只显示反应式表单输入的验证错误。

控件值访问器用于创建自定义输入。您要做的是创建一个将 Abstract 控件作为输入的简单组件。该组件可能如下所示:

TS:

@Input() public control: AbstractControl;
...

这样,您就可以访问自定义组件内部的 formControls 属性,如invalidtouchederrors
.html:

<ng-container *ngIf="control?.invalid && control?.touched">
<ul>
<li class="validation-message" *ngFor="let error of control.errors">
{{error}}
</li>
</ul>
</ng-container>

然后添加应将错误显示为输入的控件

<custom-validation-message [control]="form.get('name')"></custom-validation-message>

以下是访问自定义FormControl组件 (ControlValueAccessor(FormControl的方法。使用 Angular 8 进行测试。

<my-text-input formControlName="name"></my-text-input>
@Component({
selector: 'my-text-input',
template: '<input
type="text"
[value]="value"
/>'
})
export class TextInputComponent implements AfterContentInit, ControlValueAccessor {
@Input('value') value = '';
// There are things missing here to correctly implement ControlValueAccessor, 
// but it's all standard.
constructor(@Optional() @Self() public ngControl: NgControl) {
if (ngControl != null) {
ngControl.valueAccessor = this;
}
}

// It's important which lifecycle hook you try to access it.
// I recommend AfterContentInit, control is already available and you can still
// change things on template without getting 'change after checked' errors.
ngAfterContentInit(): void {
if (this.ngControl && this.ngControl.control) {
// this.ngControl.control is component FormControl
}
}
}

没有检查你的方法。CustomControlValueAccessor只能用于实际窗体控件。这是一种创造性的方法,它可能以某种方式起作用,但我不会这样做。

除了注入之外,还有其他方法可以访问验证组件中的FormControl

1( 定义不带FormBuilderFormGroup,以便您可以直接访问表单控件:

firstName: new FormControl('');
lastName: new FormControl('');
profileForm = new FormGroup({
firstName,
lastName
});

然后在 html 中,您可以将表单控件传递给自定义验证消息:

<custom-validation-message [control]="firstName">My special error message!</custom-validation-message>

2( 尽管如此,还是使用FormBuilder,但具有 getter 功能:

// component
get firstName() {
return this.profileForm.get('firstName') as FormControl;
}
<custom-validation-message [control]="firstName">My special error message!</custom-validation-message>

3(或如托马斯施耐特所写:通过以下方式访问模板中的控件:

<form [formGroup]="form">
<input formControlName="name" type="text" />
<custom-validation-message [control]="form.get('firstName)">My special error message!</custom-validation-message>
</form>

最新更新