问题
I created custom component representing password form control (code below is simplified).
PasswordComponent (html)
<form [formGroup]="passwordForm">
...
<input formControlName="password" type="password">
</form>
PasswordComponent (ts)
...
@Component({
selector: 'password',
templateUrl: './password.component.html',
styleUrls: ['./password.component.css'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => PasswordComponent),
multi: true
}]
})
export class PasswordComponent implements ControlValueAccessor {
passwordForm: FormGroup;
onChange = (password: string) => { };
onTouched = () => { };
constructor() {
this.passwordForm = new FormGroup({
...
password: new FormControl('')
});
this.passwordForm.valueChanges.subscribe(data => this.onChange(this.value));
}
get value(): string {
return this.passwordForm.get('password').value;
}
writeValue(password: string): void {
this.passwordForm.get('password').setValue(password);
this.onChange(this.value);
}
registerOnChange(fn: any): void { this.onChange = fn; }
registerOnTouched(fn: any): void { this.onTouched = fn; }
setDisabledState?(isDisabled: boolean): void { }
}
I use it in other components instead of standard input element:
<form [formGroup]="userForm">
...
<password formControlName="password"></password>
</form>
Validators are coming from outer form (they're not defined inside PasswordComponent)
this.userForm = fb.group({
...
password: ['', [Validators.minLength(10), Validators.maxLength(100)]]
});
My question is: how can I get <password>
element validity from inside PasswordComponent? I would like to stylize it based on validity. In other words how can I get validity of userForm's 'password' control from PasswordComponent that represents this control.
回答1:
As we can't get NgControl
instance directly from DI system since we'll get a circular dependency error. The following diagram shows why it happens if we inject NgControl
in our custom value accessor:
Now it should be clear that we have NgControl -> FormControlName -> ValueAccessor -> CustomValueAccessor -> NgControl
circular dependency
To work around it you can leverageInjector
to achieve that:
component.ts
import { NgControl } from '@angular/forms';
export class PasswordComponent implements ControlValueAccessor {
...
ngControl: NgControl;
constructor(private inj: Injector) {
...
}
ngOnInit() {
this.ngControl = this.inj.get(NgControl)
}
template.html
{{ ngControl.control.valid }}
Plunker Example
回答2:
One more way to solve this problem is to Remove the NG_VALUE_ACCESSOR from the provider and just inject NgControl. Using the NgControl instance the component will be registered as ValueAccessor.
constructor(
...,
@Optional() @Self() public ngControl: NgControl,
...,
) {
// Setting the value accessor directly (instead of using
// the providers) to avoid running into a circular import.
if (this.ngControl != null) { this.ngControl.valueAccessor = this; }
}
来源:https://stackoverflow.com/questions/45536108/access-valid-value-of-custom-form-control