1
votes

Suppose I have a list of objects and I want to change a certain object styling. I am utilizing ngClass and click event to toggle CSS class.

<ul class="container">
  <li class="item" [ngClass]="{'active': isClassVisible }" (click)="isClassVisible = !isClassVisible">1</li>
  <li class="item" [ngClass]="{'active': isClassVisible }" (click)="isClassVisible = !isClassVisible;">2</li>
  <li class="item" [ngClass]="{'active': isClassVisible }" (click)="isClassVisible = !isClassVisible;">3</li>
  <li class="item" [ngClass]="{'active': isClassVisible }" (click)="isClassVisible = !isClassVisible;">4</li>
</ul>

then in component I have

export class MyComponent {
  isClassVisible: false;
}

and CSS

.active {
  background: black;
}

However with this approach, when I click on an element inside list, the CSS class is applied to all of them, but not the element I clicked.

3

3 Answers

6
votes

Why not make a directive to handle it

import { Directive, ElementRef, Renderer2, HostListener } from '@angular/core';
@Directive({ selector: '[myActive]' })
export class ActiveDirective {

    private _isActive = false;

    constructor(private el: ElementRef, private renderer: Renderer2) {

    }

    @HostListener('click', ['$event'])
    onClick(e) {
        e.preventDefault();
        this._isActive = !this._isActive;
        if (this._isActive) {
          this.renderer.addClass(this.el.nativeElement, 'active');
        } else {
          this.renderer.removeClass(this.el.nativeElement, 'active');
        }
    }
}

Then use it like this

<ul class="container">
  <li class="item" myActive>1</li>
  <li class="item" myActive>2</li>
</ul>
  • The Renderer class has been marked as deprecated since Angular version 4 and been completely removed since Angular version 9. You can use Renderer2 in lower angular versions too. - ref
  • Renderer2 Docs
0
votes

because you are using same variable in all the li's and when you click one of them style is applying to all of them.

Try using diff diff variable on each li

or use like this

<ul class="container">
  <li *ngFor = 'let n of num' class="item" [ngClass]="{'active': selectedLi == n }" (click)="selectedLi = n">{{n}}</li>
</ul>

export class MyComponent {
  isClassVisible: false;
  num = [1,2,3,4,5]
}
0
votes

You can achieve this by simply implementing a separate directive. To handle this click event use @HostListener and for binding the property use @HostBinding as:

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

@Directive({
  selector : '[appActive]'
})
export class ActivelinkDirective{
  @HostBinding('class.active') isActive=false;

  @HostListener('click') toActive(){
    this.isActive = !this.isActive;
  }
}

And then for the view use this directive as:

<ul class="container">
  <li class="item" appActive>1</li>
  <li class="item" appActive>2</li>
  <li class="item" appActive>3</li>
</ul>