1

I have the following input element:

 <input
        range
        [btnClass]="'close_input_button'"
        type="text"
        class="reset-border-right"
        formControlName="parentId1Name"
      />

As you can see I use directive:

 range [btnClass]="'close_input_button'"

Directive looks like:

@Directive({
  selector: "[range]"
})
export class RangeDirective implements OnInit {
   @HostListener("change", ["$event"]) ngOnChanges(value: any) {
    console.log(value);
  }
}

Why when I set a new value for input using reactive form it does trigger change event in directive?

this.form.get("parentId1Name").setValue('New value');

Full directive is:

import {
  Input,
  HostListener,
  OnInit,
  OnChanges,
  SimpleChanges
} from "@angular/core";
import { Renderer2 } from "@angular/core";
import { ElementRef } from "@angular/core";
import { Directive } from "@angular/core";

@Directive({
  selector: "[range]"
})
export class RangeDirective implements OnInit, OnChanges {
  constructor(private elementRef: ElementRef, private renderer: Renderer2) {}

  readonly _elements = ["INPUT", "SELECT", "TEXTAREA"];
  private newDomElement: any;

  @Input() btnClass: string;
  @Input() model: any;
  @Input() position: string = "right";

  ngOnInit(): void {
    const parent = this.elementRef.nativeElement.parentNode;
    const reference = this.elementRef.nativeElement;

    this.elementRef.nativeElement.parentNode.style.position = "relative";
    this.newDomElement = this.createButton();
    this.renderer.insertBefore(parent, this.newDomElement, reference);
  }

  @HostListener("keyup", ["$event"]) ngKeyup(value: any) {
    this.eventHandler(value);
  }

  @HostListener("change", ["$event"]) ngChange(value: any) {
    this.eventHandler(value);
  }

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

  eventHandler(value: any) {
    if (!value.srcElement) return;
    const _value = value.srcElement.value.toString().trim();
    if (_value) {
      this.newDomElement.style.display = "flex";
    } else {
      this.newDomElement.style.display = "none";
    }
  }

  createButton() {
    let closeButton = document.createElement("div");
    closeButton.innerHTML = '<i class="material-icons">clear</i>';
    closeButton.className = this.btnClass;
    closeButton.className += " " + this.position;
    closeButton.style.display = "none";
    closeButton.onclick = () => {
      closeButton.style.display = "none";
      this.elementRef.nativeElement.value = null;
    };

    return closeButton;
  }

}

1 Answer 1

2

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

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

    ngOnChanges(changes: SimpleChanges){
      if(changes.input){
        console.log('input changed');
      }
    }
}
7
  • I have tried it does not work, I dont see ` console.log('input changed');`
    – POV
    Commented Oct 31, 2019 at 15:35
  • Instead @Input() public range: any; @Input() public input: any; I use private elementRef: ElementRef
    – POV
    Commented Oct 31, 2019 at 15:35
  • 1
    Could you provide plunker or stackblitz. Easy way to fix.
    – Vipul
    Commented Oct 31, 2019 at 15:36
  • I can post full directive, see question please
    – POV
    Commented Oct 31, 2019 at 15:37
  • Could you check below stackoverflow link: This might be useful. stackoverflow.com/questions/52609806/…
    – Vipul
    Commented Oct 31, 2019 at 15:45