I'm trying to show a clarifying "Required" placeholder text for all input fields that have "required" attribute set to true.
So basically the same as
<mat-form-field>
<input formControlName="fieldName" matInput required="true" placeholder="Required">
</mat-form-field>
But programmatically for all required fields. Form fields "required" status is set at the component initialization based on various conditions.
If there is a way to do this for all components / pages of the angular app, not just for one component that would be even better!
To apply a directive to several elements we use the selector
In this case the selector is a tag "input" with an attribute "formControl" or attribute "formControlName"
import {
Directive,
ElementRef,
} from '@angular/core';
import { NgControl, Validators } from '@angular/forms';
@Directive({
selector: 'input[formControlName],input[formControl]',
standalone: true,
})
export class AddPlaceholderDirective {
constructor(private control: NgControl, private element: ElementRef) {}
ngAfterViewInit() {
if (this.control.control?.hasValidator(Validators.required) &&
!this.element.nativeElement.placeholder) {
this.element.nativeElement.placeholder = 'required';
}
}
}
Update a brief explain:
A directive can be "structural directives" and "attributes directives".
An attribute directive give new characteristic to our htmlElements or even to ours components, but How works?
When we have a selector like [myDirective]
all the HTMLElements with this "attribute" are improve with the new characteristic. (this is the reason for the name of attribute directive)
e.g., when have
@Directive({
selector: '[myDirective]',
standalone: true,
})
export class MyDirective {
constructor(private element: ElementRef) {
console.log("I'm a super div")
}
}
//and write
<div myDirective>Hello</div>
This div it's not a simple div, else a "super div" (yes, only say in console "I'm a super div", but make "something different that a simple div")
Well, the structural directive have a "selector" that in general is a simple string between [``]
but the selectors can be different, see the docs
So, a selector like input[formControl]
give new super power to all the input with an attribute "formControl" and a selector like input[type="radio"]
give new super power to all the input with an attribute type who was "radio".
I know that formControl was another directive but it's also an attribute.
NOTE: the good of an "attribute directive" is that, as is applied to an HTMLElement or to a Component, we can get in constructor the htmlElement or the component this is the reason we can use
constructor(private elementRef:ElementRef,control:NgControl){}
The "elementRef" we have in all the attributes directives and is the own "htmlElement" where we add the attribute.
The "ngControl" is because we have an input with ngModel of FormControl or FormControlName