在使用自定义输入组件时,我遇到了一些奇怪的行为。
首先,我建立了一个简单的抽象类,它具有组件的主要“功能”和方法,然后是具有很少代码的输入组件:
// Abstract class
export abstract class BaseFormInput<T> implements ControlValueAccessor, Validator, AfterViewInit, OnDestroy {
@Input() label: string
@Output() onChange: EventEmitter<T> = new EventEmitter<T>()
private changeInternal: (obj: T) => void
private changeSub: Subscription
private disabled$ = new BehaviorSubject(false)
private required$ = new BehaviorSubject(false)
public input = new FormControl(null)
ngOnDestroy() {
this.changeSub.unsubscribe()
}
ngAfterViewInit() {
this.changeSub = this.input.valueChanges.subscribe(v => {
if (!this.disabled$.getValue()) {
this.onChange.emit(v)
this.changeInternal(v)
}
})
}
writeValue = (obj: T) => this.input.setValue(obj)
registerOnChange = (fn: (obj: T) => void) => this.changeInternal = fn
registerOnTouched = (_fn: (obj: any) => void) => {}
setDisabledState = (isDisabled: boolean) => this.disabled$.next(isDisabled)
validate(control: AbstractControl): ValidationErrors {
this.required$.next(control.hasValidator(Validators.required))
// THIS LINE HAS WEIRD BEHAVIOR
console.log(control, control.errors)
return null
}
public get isDisabled$(){
return this.disabled$.asObservable()
}
public get isRequired$(){
return this.required$.asObservable()
}
}
输入组件简单设计如下:
@Component({
selector: "ec-input-text",
template: `<div class="form-control">
<label *ngIf="label">
{{ label }}
<span *ngIf="isRequired$ | async">*</span>
</label>
<input *ngIf="type !== 'textarea'" [type]="type" [formControl]="input" [attr.disabled]="isDisabled$ | async" />
<textarea *ngIf="type === 'textarea'" [formControl]="input" [attr.disabled]="isDisabled$ | async"></textarea>
<ng-template></ng-template>
</div>`,
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => InputTextComponent), multi: true },
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => InputTextComponent), multi: true }
]
})
export class InputTextComponent extends BaseFormInput<string> {
@Input() type: "text" | "password" | "email" | "textarea" = "text"
@Input() maxLength: number
}
最后,我创建了一个使用输入的注册组件。
HTML:
<form [formGroup]="form">
<ec-input-text label="First name" formControlName="firstName" />
<ec-input-text label="Last name" formControlName="lastName" />
<ec-input-text label="E-mail" formControlName="email" type="email" />
<ec-input-text label="Password" formControlName="password" type="password" />
</form>
注册组件的 TS 具有如下公共属性:
public form = new FormGroup({
firstName: new FormControl(null, [Validators.required, Validators.maxLength(50)]),
lastName: new FormControl(null, [Validators.required, Validators.maxLength(50)]),
email: new FormControl(null, [Validators.required, Validators.maxLength(100)]),
password: new FormControl(null, Validators.required)
})
现在,问题如下:在抽象类的validate方法中(我在其中添加了注释),我尝试记录控制错误,但出现了奇怪的行为:记录formControl时,我可以在控制台中看到属性errors为空,但如果我记录control.errors,则会记录:
{ required: true }
即使控件有效,并且我输入了值(实际上,control.value有一个值并且结果有效)。因此,如果我这样做:
console.log(control)
我将其扩展,错误为空(预期行为,正确!)
但如果我这么做:
console.log(control.errors)
它被重视了(不正确,控制是有效的!)
我该如何解决这个问题?提前致谢!