Reputation: 10324
I'm using an angular child component that implements ControlValueAccessor
with reactive forms. The child component is essentially just wrapping another component with a few extra things. So in the parent, when I do this:
<app-child formControlName="foo"></app-child>
the form group knows that foo is required. How, in the child component, do I determine that it's required? I need to add the required attribute in the HTML to the component being wrapped, essentially.
Upvotes: 0
Views: 3252
Reputation: 6706
If the child component should be always required, then you can implement the Validator
interface, and provide the NG_VALIDATORS token in the child component, to sync the invalid state with the parent form-group.
You can try the following to achieve that in this case:
@Component({
// ...
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ChildComponent),
multi: true,
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => ChildComponent),
multi: true,
},
],
})
export class ChildComponent implements ControlValueAccessor, Validator {
innerCtrl: FormControl; // Use it to access the inner component value and invalid state.
onValidationChange: () => void;
validate(control: AbstractControl): ValidationErrors | null {
if (this.innerCtrl.invalid) {
return { invalid: true };
} else {
return null;
}
}
registerOnValidatorChange?(fn: () => void): void {
this.onValidationChange = fn;
}
// ...
}
Otherwise, if the child component shouldn't always be required, then you can inject the NgControl
from the child component, to check if it has the required
validator or not, using the AbstractControl.hasValidator() API which has been introduced in Angular 12.2.0 (Like how MatInput shows required asterisk when using required validator)
You can try the following to achieve that in this case:
@Component({
// ...
})
export class ChildComponent implements ControlValueAccessor {
get required(): boolean {
return this.ngControl?.control?.hasValidator(Validators.required);
}
constructor(@Optional() @Self() private ngControl: NgControl);
// ...
}
Upvotes: 4