oooyaya
oooyaya

Reputation: 1803

Angular2 - ngclass on directive selector

I'm using the latest Angular 2 beta (45?) and am trying to attach an ngClass to the element identified by the directive selector. The variable used to toggle the class does not update.

I suspect it's one of two things:

  1. Angular2 just doesn't work that way, so it's a scoping issue; if I put a div inside of the directive selector element and attach the ngClass to that div, it works. I'd prefer not to do that though.
  2. Because i'm reacting to a window event. I've tried using Observers, setTimeout hackery, and zones. No luck.

Is there a way to do what I'm trying to do? Is that just not how it's done anymore?

Sample code written from memory since I do not have access to it presently:

@Directive({
    selector: "nav",
    templateUrl: "templates/nav.html"
});

export class NavComponent {
    isOpen:Boolean = false;

    onScroll(e) {
        this.isOpen = true;
    }

    window.onscroll = (e) => this.onScroll.call(this);  // .call seemed necessary, because otherwise the scope of 'this' changed to window instead of the directive  
}

The following does not work:

index.html

<nav [ngClass]="{open: isOpen}"></nav>

templates/nav.html

<a href="#">whatever</a>
...
<a href="#">whatever 2</a>

The following does work:

index.html

<nav></nav>

templates/nav.html

<div [ngClass]="{open: isOpen}">
    <a href="#">whatever</a>
    ...
    <a href="#">whatever 2</a>
</div>

Upvotes: 3

Views: 1578

Answers (2)

Mark Rajcok
Mark Rajcok

Reputation: 364747

In addition to Günter's answer, use a host listener instead of assigning an event handler to window.onscroll. Then Angular change detection will run and actually update the CSS class when you scroll. (Otherwise, some other event will need to happen before the view gets updated.)

@Component({
    selector: "nav",
    template: `<a href="#">whatever</a>
      <a href="#">whatever 2</a>`,
    host: {
      '(window:scroll)': 'onScroll($event)',   //  <<------
      '[class.open]': 'isOpen'
    }
})
export class NavComponent {
  isOpen:Boolean = false;
  onScroll(e) {
    this.isOpen = true;
  }
}

@Component({
  selector: 'my-app',
  template: `<nav></nav>
    <div *ngFor="#row of dummyArray; #i = index">row {{i}}</div>`,
  styles: ['.open { background-color: lightblue }']
  directives: [NavComponent]
})
export class AppComponent {
  dummyArray = new Array(100);
  constructor() { console.clear(); }
}

Plunker

Upvotes: 3

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 658067

isOpen in

<nav [ngClass]="{open: isOpen}"></nav>

refers to the parent component of <nav>, the component that has <nav> in its template.

If you want to set the class on the directives host, use

@Directive({
    selector: "nav",
    templateUrl: "templates/nav.html",
    host: {'[class.open]': 'isOpen'}
});
export class NavComponent {
    isOpen:Boolean = false;

    onScroll(e) {
        this.isOpen = true;
    }
}

Upvotes: 1

Related Questions