We can implement an attribute directive that adds a required
attribute to your element when the corresponding form control has the Validators.required
validator:
import { Directive, ElementRef, OnInit, ViewContainerRef } from '@angular/core';
import { FormControlName, NgControl, Validators } from '@angular/forms';
@Directive({
selector: '[formControl], [formControlName]',
standalone: true,
})
export class FormControlRequiredAttributeDirective implements OnInit {
constructor(private elementRef: ElementRef, private ngControl: NgControl) {}
ngOnInit(): void {
if (
(this.ngControl instanceof FormControlName || this.ngControl instanceof FormControlDirective) &&
this.ngControl.control.hasValidator(Validators.required)
) {
this.elementRef.nativeElement.required = 'true';
}
}
}
When you import the directive into your component, it will work:
@Component({
imports: [ReactiveFormsModule, FormControlRequiredAttributeDirective],
// ...
})
class LoginFormComponent {
formGroup: FormGroup = new FormGroup({
email: new FormControl('', Validators.required),
});
}
<form [formGroup]="formGroup">
<label>
<span>Email</span>
<input type="email" formControlName="email" />
</label>
</form>
This way, the validators serve as the single source of truth, eliminating the need for repetition.