Angular 自定义表单控件永远不会弄脏我的表单
Angular Custom Form Control never make my Form dirty
我创建了一个自定义表单控件,但每当值发生变化时,它都不会将表单标记为脏。我不明白应该做什么。
这是我的自定义组件的代码:
import { ThrowStmt } from '@angular/compiler';
import { Component, forwardRef, Input, OnInit, Output } from '@angular/core';
import { ControlValueAccessor, FormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms';
import { EventEmitter } from 'events';
@Component({
selector: 'app-multiple-checkbox',
templateUrl: './multiple-checkbox.component.html',
styleUrls: ['./multiple-checkbox.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MultipleCheckboxComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => MultipleCheckboxComponent),
multi: true
}]
})
export class MultipleCheckboxComponent implements OnInit, ControlValueAccessor {
value = [];
disabled = false;
@Input() public options: { key, value }[];
@Output() haschanged = new EventEmitter();
onChange: any = (key) => {
this.haschanged.emit(key, this.value);
}
onTouched: any = () => { };
constructor() { }
validate({ value }: FormControl) {
const isNotValid = this.value.length === 0;
return isNotValid && {
invalid: true
};
}
ngOnInit(): void {
}
evaluate(event, key): void {
if (event.target.checked) {
this.value.push(key);
} else {
this.value.splice(this.value.findIndex(i => key === i), 1);
}
this.onTouched(this.value);
this.onChange(key, this.value);
}
isChecked(key): boolean {
return this.value.findIndex(e => e === key) > -1;
}
writeValue(value: any): void {
this.value = value;
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onChange = fn;
}
setDisabledState?(isDisabled: boolean): void {
this.disabled = isDisabled;
}
}
视图如下:
<div *ngFor="let option of options">
<label [attr.for]="option.key">{{option.value}}</label>
<input [id]="option.key" type="checkbox" [checked]="isChecked(option.key)" [disabled]="disabled" (change)="evaluate($event, option.key)">
</div>
缺少什么使表格变脏?
On blur (or equivalent), your class should call the registered
function to allow the forms API to update itself:
host: {
'(blur)': '_onTouched()'
}
change 事件发生同样的事情,而且你没有达到 ControlValueAccessor
的目的,它应该与 ngModel
一起使用,或者与 FormControls
的 ReactiveForms 一起使用
这是在表单中用于复选框的指令
所以你可以看到一个 class 是如何实现的 ControlValueAccessor
这可能是一个好的开始
您的实施中有几处不太正确。
onChange
函数将在行 onChange = fn
中分配一个值,因此不会使用下面的代码
onChange: any = (key) => {
this.haschanged.emit(key, this.value);
}
所以将其更改为 onChange: any;
- 下面一行重新赋值了我们的
onChange
函数,这里肯定会出现意想不到的结果
registerOnTouched(fn: any): void {
this.onChange = fn;
}
把上面的改成
onTouched: any;
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
删除EventEmitter
。您可能正在尝试发出事件,但是在使用 ControlValueAccessor
时 angular 应该为您完成剩下的工作,包括事件发出。另外 非常重要 EventEmitter
是从 @angular/core
而不是从 events
导入的
更改评估函数以调用 onTouched
和 onChange
函数,如下所示
evaluate(event, key): void {
if (event.target.checked) {
this.value.push(key);
} else {
this.value.splice(this.value.findIndex(i => key === i), 1);
}
this.onChange(this.value);
this.onTouched();
}
完成这些更改后,Angular 将为您完成剩下的工作,包括将表单设置为脏状态、触摸状态和有效状态
我创建了一个自定义表单控件,但每当值发生变化时,它都不会将表单标记为脏。我不明白应该做什么。
这是我的自定义组件的代码:
import { ThrowStmt } from '@angular/compiler';
import { Component, forwardRef, Input, OnInit, Output } from '@angular/core';
import { ControlValueAccessor, FormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms';
import { EventEmitter } from 'events';
@Component({
selector: 'app-multiple-checkbox',
templateUrl: './multiple-checkbox.component.html',
styleUrls: ['./multiple-checkbox.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MultipleCheckboxComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => MultipleCheckboxComponent),
multi: true
}]
})
export class MultipleCheckboxComponent implements OnInit, ControlValueAccessor {
value = [];
disabled = false;
@Input() public options: { key, value }[];
@Output() haschanged = new EventEmitter();
onChange: any = (key) => {
this.haschanged.emit(key, this.value);
}
onTouched: any = () => { };
constructor() { }
validate({ value }: FormControl) {
const isNotValid = this.value.length === 0;
return isNotValid && {
invalid: true
};
}
ngOnInit(): void {
}
evaluate(event, key): void {
if (event.target.checked) {
this.value.push(key);
} else {
this.value.splice(this.value.findIndex(i => key === i), 1);
}
this.onTouched(this.value);
this.onChange(key, this.value);
}
isChecked(key): boolean {
return this.value.findIndex(e => e === key) > -1;
}
writeValue(value: any): void {
this.value = value;
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onChange = fn;
}
setDisabledState?(isDisabled: boolean): void {
this.disabled = isDisabled;
}
}
视图如下:
<div *ngFor="let option of options">
<label [attr.for]="option.key">{{option.value}}</label>
<input [id]="option.key" type="checkbox" [checked]="isChecked(option.key)" [disabled]="disabled" (change)="evaluate($event, option.key)">
</div>
缺少什么使表格变脏?
On blur (or equivalent), your class should call the registered function to allow the forms API to update itself:
host: {
'(blur)': '_onTouched()'
}
change 事件发生同样的事情,而且你没有达到 ControlValueAccessor
的目的,它应该与 ngModel
一起使用,或者与 FormControls
的 ReactiveForms 一起使用
这是在表单中用于复选框的指令
所以你可以看到一个 class 是如何实现的 ControlValueAccessor
这可能是一个好的开始
您的实施中有几处不太正确。
onChange
函数将在行onChange = fn
中分配一个值,因此不会使用下面的代码
onChange: any = (key) => {
this.haschanged.emit(key, this.value);
}
所以将其更改为 onChange: any;
- 下面一行重新赋值了我们的
onChange
函数,这里肯定会出现意想不到的结果
registerOnTouched(fn: any): void {
this.onChange = fn;
}
把上面的改成
onTouched: any;
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
删除
导入的EventEmitter
。您可能正在尝试发出事件,但是在使用ControlValueAccessor
时 angular 应该为您完成剩下的工作,包括事件发出。另外 非常重要EventEmitter
是从@angular/core
而不是从events
更改评估函数以调用
onTouched
和onChange
函数,如下所示
evaluate(event, key): void {
if (event.target.checked) {
this.value.push(key);
} else {
this.value.splice(this.value.findIndex(i => key === i), 1);
}
this.onChange(this.value);
this.onTouched();
}
完成这些更改后,Angular 将为您完成剩下的工作,包括将表单设置为脏状态、触摸状态和有效状态