skip to Main Content

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!

2

Answers


  1. Looks like you need a directive that will do it for you, we can create a directive addPlaceholder which will first get the formControlName using getAttribute and then through the controlContainer.control get the parent form, then finally we get access to the FormControl of the element, check if has required validator and then finally set the placeholder

    Please find below working example!

    directive

    import { Directive, ElementRef, Inject, Input } from '@angular/core';
    import { ControlContainer, FormControl, Validators } from '@angular/forms';
    
    @Directive({
      selector: '[addPlaceholder]',
      standalone: true,
    })
    export class AddPlaceholderDirective {
      @Input() customPlaceholder = 'required';
    
      constructor(
        @Inject(ControlContainer) private container: ControlContainer,
        private element: ElementRef
      ) {}
    
      ngAfterViewInit() {
        const formControlName =
          this.element.nativeElement.getAttribute('formControlName');
        const control: FormControl = this.container?.control?.get(
          formControlName
        ) as FormControl;
        if (control.hasValidator(Validators.required)) {
          this.element.nativeElement.placeholder = 'required!';
        }
      }
    }
    

    main.ts

    import { Component } from '@angular/core';
    import {
      FormControl,
      FormGroup,
      ReactiveFormsModule,
      Validators,
    } from '@angular/forms';
    import { bootstrapApplication } from '@angular/platform-browser';
    import 'zone.js';
    import { AddPlaceholderDirective } from './add-placeholder.directive';
    
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [ReactiveFormsModule, AddPlaceholderDirective],
      template: `
        <form [formGroup]="form">
      <input type="text" formControlName="test" addPlaceholder/>
      <input type="text" formControlName="test2" addPlaceholder/>
      <input type="text" formControlName="test3" addPlaceholder/>
    </form>
      `,
    })
    export class App {
      form = new FormGroup({
        test: new FormControl('', Validators.required),
        test2: new FormControl('', Validators.required),
        test3: new FormControl(''),
      });
    }
    
    bootstrapApplication(App);
    

    stackblitz

    Login or Signup to reply.
  2. 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';
        }
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search