Detect when input value changed in directive

AngularAngular DirectiveAngular2 Directives

Angular Problem Overview


I'm trying to detect when the value of an input changed in a directive. I have the following directive:

    import { ElementRef, Directive, Renderer} from '@angular/core';
    
    @Directive({
        selector: '[number]',
        host: {"(input)": 'onInputChange($event)'}
    })
    
    export class Number {
    
        constructor(private element: ElementRef, private renderer: Renderer){
    
        }
        onInputChange(event){
            console.log('test');
        }
    }

The problem in this directive is that it detects only when there is an input and not when the value changes programatically. I use reacive form and sometimes I set the value with the patchValue() function. How can I do so the change function gets triggered?

Angular Solutions


Solution 1 - Angular

You need to make an input property of input and then use the ngOnChanges hook to tell when the input property changes.

@Directive({
    selector: '[number]'
})
export class NumberDirective implements OnChanges {
    @Input() public number: any;
    @Input() public input: any;

    ngOnChanges(changes: SimpleChanges){
      if(changes.input){
        console.log('input changed');
      }
    }
}

Plunkr

Stackblitz

Solution 2 - Angular

There is a better way to detect when an Input property changes, it's considered a best practice and it's also used in the *ngIf implementation.

You just need to postpone the keyword set after Input(), in this way you combine the @Input() decorator with a setter, and it gets called all the times the value changes.

_rows: number; @Input() set rows(value: number) { if (this.value < 0) { console.error('The number of rows must be positive'); this._rows = 2; return; }

  this._rows = value;
}

If you want to compare the new value with the previous value, you must store the variable in a class property, and retrieve it the second time the method got called:

private previousValue: any = T;

@Input() set myInputName(value: T) {
  console.log(`Previous value was: ${this.previousValue}`);
  console.log(`New value is: ${value}`);
  this.previousValue = value;  
}

Solution 3 - Angular

As of Angular 9+ I can verify that the snippet below is the correct solution. It's best to avoid ngOnChanges whenever possible for several reasons and use the correct host listener event instead. The below example will get the current input value on keyup. You can easily customize this code snippet for whatever you need on an input directive.

@Directive({ selector: '[appMyDirective]', }) export class MyDirective { // Add whatever event you want to track here @HostListener('keyup', ['$event']) public onKeyup(event: KeyboardEvent): void { const value = (event.target as HTMLInputElement).value; console.log(value); } }

Solution 4 - Angular

You can also use HostListener. For more information about HostListener, you can go through this link. Here is the code.

import {Directive, ElementRef, HostListener} from '@angular/core';


@Directive({
       selector: '[number]'
 })

export class NumberDirective {

    @Input() public number: any;
    @Input() public input: any;

    constructor(private el: ElementRef) {}

    @HostListener('change') ngOnChanges() {
        console.log('test');
    }

}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionncohenView Question on Stackoverflow
Solution 1 - AngularTeddy SterneView Answer on Stackoverflow
Solution 2 - AngularCristian TraìnaView Answer on Stackoverflow
Solution 3 - AngularAsh BlueView Answer on Stackoverflow
Solution 4 - AngularTushar GhoshView Answer on Stackoverflow