Search code examples
angularvalidation

My Angular component is not being updated during validation


I have a component to display a validation message:

@Component({
  selector: 'app-error-msg',
  template: `
  <div *ngIf="showItem()" [class]="'text-error-small {class}'"> 
    <ng-content></ng-content>
  </div>
`,
  styleUrls: ['./error-msg.component.css']
})
export class ErrorMessageComponent {
  @Input() item: any;
  @Input() class = "";
  @Input() useTouched = true;

  showItem() {
    if(this.item.valid)
      return false;
    if(this.useTouched && ! this.item.touched)
      return false;
    return true;
  }
}

The idea is to use it like this:

    <input class="p-1" myValidator [(ngModel)]="param.parameter" #sample/>
    <app-error-msg [item]="sample">
        Please enter a valid name.
    </app-error-msg>

Where myValidator is a validator (which works correctly.) The problem is that although the validator is called on each keystroke, the app-error-msg component does not re-evaluate the html. Any suggestions what I am doing wrong.


Solution

  • You need to get the form control using the template variable export (#sample="ngModel"), for ngModel directive, it supports the export of NgModel using the name as ngModel, In the source code ( ng_model.ts: 137 we can see this. Once we export this your validator seems to work fine!

    main.ts

    import { CommonModule } from '@angular/common';
    import { Component } from '@angular/core';
    import { FormsModule } from '@angular/forms';
    import { bootstrapApplication } from '@angular/platform-browser';
    import 'zone.js';
    import { ErrorMsgComponent } from './error-msg/error-msg.component';
    
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [CommonModule, FormsModule, ErrorMsgComponent],
      template: `
        <input class="p-1" myValidator [(ngModel)]="name" #sample="ngModel" required/>
        <app-error-msg [item]="sample">
            Please enter a valid name.
        </app-error-msg>
      `,
    })
    export class App {
      name = 'Angular';
    }
    
    bootstrapApplication(App);
    

    error msg

    import { CommonModule } from '@angular/common';
    import { Component, Input, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-error-msg',
      template: `
        <div *ngIf="showItem()" [class]="'text-error-small' + class"> 
          <ng-content></ng-content>
        </div>
      `,
      standalone: true,
      imports: [CommonModule],
    })
    export class ErrorMsgComponent {
      @Input() item: any;
      @Input() class = '';
      @Input() useTouched = true;
    
      showItem() {
        if (this.item.valid) return false;
        if (this.useTouched && !this.item.touched) return false;
        return true;
      }
    }
    

    stackblitz