Search code examples
angulartypescriptscopeangular-directive

Angular 2.4.0 Target NgClass Inside of Attribute Directive


How would I go about using NgClass inside of a custom attribute directive to change the main elements CSS class?

If I have something like this:

@Component({
  selector: 'my-app',
  template: `
    <div>
      <div class="box" myDir [ngClass]="{'blue': blue, 'red': red}">   </div>
    </div>
  `,
});

And then, inside of that myDir directive, something like this:

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

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

export class MyDirDirective {
  blue: boolean;
  red: boolean;

  constructor() { 
  }

  ngOnInit() {
  } 

  @HostListener('mouseenter', ['$event'])
  onMouseEnter(event) {
    event.preventDefault();
    event.stopPropagation();

    this.blue = true;
    this.red = false;

    console.log('mouseenter');
  }

  @HostListener('mouseleave', ['$event'])
  onMouseLeave(event) {
    event.preventDefault();
    event.stopPropagation();

    this.blue = true;
    this.red = false;

    console.log('mouseleave');
  }

Do I not have access to the scope in which blue and red reside in? If I create a toggle, I can update those values with a button, but it doesn't seem like I can do it from within the directive itself. Is this an accurate observation and should I be doing it this way or is there an alternative that I'm not seeing in the docs?


Solution

  • Properties blue\red in your case reside in the scope of parent component my-app .

    You may create an Output event inside your directive which can be subscribed in the parent component to change the value,

    Something similar to below,

    @Directive({
      selector: '[myDir]'
    })
    export class MyDirDirective {
      blue: boolean;
      red: boolean;
    
      @Output() myEvent = new EventEmitter();
    
      @HostListener('mouseenter', ['$event'])
      onMouseEnter(event) {
        event.preventDefault();
        event.stopPropagation();
        this.myEvent.next('blue');
      }
    
      @HostListener('mouseleave', ['$event'])
      onMouseLeave(event) {
        event.preventDefault();
        event.stopPropagation();
        this.myEvent.next('red');
      }
    }
    

    and subscribe to this event in parent component to update color to blue\red.

    @Component({
      selector: 'my-app',
      template: `<h1>Hello {{name}}</h1>
      <div class="box" myDir (myEvent)="myEvent($event)"
            [ngClass]="{'blue': color === 'blue', 'red': color === 'red'}"> Hello World!!</div>
      `,
      styles:[`
      .blue{
        border: 1px solid blue;
      }
      .red{
         border: 1px solid red;
      }`]
    })
    export class AppComponent { 
      name = 'Angular';
      color = 'blue';
    
      myEvent(val){
        this.color = val;
      }
    }
    

    Check this Plunker!!

    Hope this helps!!