2

I didn't know how to properly formulate my question so I'll try to explain myself here :

In my Angular 7 app, I have a navbar with icons as menu items.

On click, I want them to get a certain class, and the class has to disapear 2 seconds later.

I have 7 elements, here's 2 as an example :

        <li class="fushia-icon">
            <a routerLink="/savoir" routerLinkActive="fushia-icon-active" class="animated"
               [class.flip]="this.iconIsClicked" (click)="iconClicked(this.iconIsClicked = true)">
            </a>
        </li>


        <li class="beige-icon">
            <a routerLink="/diplomes" routerLinkActive="beige-icon-active" class="animated"
               [class.flip]="this.iconIsClicked" (click)="iconClicked(this.iconIsClicked = true)">  
            </a>
        </li>

In my ts file I did this :

 iconClicked(icon){
        setTimeout(()=> {
            icon = false
        }, 2000)
    }

But that doesnt do what I want at all since they both get the class, and the iconIsClicked value doesnt return to the element to be analysed (obvious).

I know I could create 7 functions with 7 variables so that each icon has its own stuff, but I'm looking for a quicker way without duplicating code.

Thank

B.Benjo
  • 563
  • 4
  • 13
naspy971
  • 1,137
  • 2
  • 13
  • 31

3 Answers3

4

You can use a template reference variable and add/remove (Element.classList methods) .

HTML

<li class="fushia-icon">
    <a #fushiaIcon class="animated" (click)="iconClicked(fushiaIcon)"></a>
</li>
<li class="beige-icon">
    <a #beigeIcon class="animated" (click)="iconClicked(beigeIcon)"></a>
</li>

TS

iconClicked(menuIcon: HTMLElement) {
    menuIcon.classList.add('flip');

    setTimeout(()=> {
        menuIcon.classList.remove('flip');
    }, 2000)
}
Chris Tapay
  • 1,004
  • 10
  • 21
2

So the goal is to use the same method for each menu. The simple choice here is to use a Directive that can easily do what we want to achieve.

I think you can remember things like this: a directive allow you to control the view

I managed to do this easily by using an HostListener with an onClick event on each li

You have the stackblitz here


extract of: class-changer.directive.ts

constructor(private _ren: Renderer2, private _el: ElementRef) { }

@HostListener('click') onClick() {
    this._ren.addClass(this._el.nativeElement, 'bg-red');
    setTimeout(() => {
      this._ren.removeClass(this._el.nativeElement, 'bg-red');
    }, 2000)
  }

EDIT
I update my stackblitz. Like this, you can add and remove class easily !

B.Benjo
  • 563
  • 4
  • 13
1

There are more than one issues in your code.

1- You need to use [ngClass] instead of [class].

2- You shouldn't use this in template files. this.iconIsClicked is not a valid value.

3- What are you trying to accomplish by calling iconClicked(this.iconIsClicked = true)? It does not make sense as you pass a primitive (meaning you are not passing by reference). Therefore modifications in the iconClicked() method does not affect template as its scope is ended when function returns.

If you try to add css class .flip to the clicked li, there are several thing you can do. Maybe you can do like the following. Since your li items are static, you need to give each one of them a template reference such as #diplomesLiRef and pass it to the component's method.

Template file

<li class="beige-icon">
    <a routerLink="/diplomes" 
        routerLinkActive="beige-icon-active"
        #diplomesLiRef
        class="animated"
        (click)="toggleClass(diplomesLiRef, 'flip')">  
    </a>
</li>

Component File

toggleClass = (liRef, cssClass) => {
    liRef.classList.add(cssClass);
    setTimeout(() => {liRef.classList.remove(cssClass)},2000);
}

But, as the commenters on your question stated, the best way to accomplish what you need is to create a directive.

Harun Yilmaz
  • 8,281
  • 3
  • 24
  • 35
  • He can totally use [class.flip], it's allowed ! see here: https://toddmotto.com/ng-class-angular-classes#property-binding-with-class – B.Benjo Jan 25 '19 at 13:51
  • @BenThie You are right. The usage is valid: [https://stackoverflow.com/a/45321551/1331040](https://stackoverflow.com/a/45321551/1331040). Thanks for clarification. – Harun Yilmaz Jan 25 '19 at 13:59
  • @HarunYılmaz No problem ;) – B.Benjo Jan 25 '19 at 14:00