cssangularmouseovermouseout

How to add class(es) to elements generated by ngFor on hover?


Problem: I have some html that uses *ngFor to generate a bunch of divs, all with the same class. I want to be able to add an active class to single elements. I keep running into the issue though of having that class applied to all of my elements instead of just one.

HTML:

  <div class="feed" infiniteScroll [infiniteScrollDistance]="2" [infiniteScrollThrottle]="50" (scrolled)="onScroll()" >
    <div class="mentions" *ngFor = 'let item of feed; let i = index;'>
    <div class="content-wrapper">
      <img src={{item.image}}>
      <div class="content-text">
        <div>{{item.name}}</div><br>
        <div>{{item.text}}</div><br>
        <div>{{item.followers}}</div><br>
      </div>
    </div>
    <div class="votebtn"> 
<button mat-button matSuffix mat-icon-button aria-label="UpVote" id = u-{{item.source}} class="UpVote" (click)="vote(i, item, 'keep')">
      <mat-icon>thumb_up</mat-icon>
    </button>
<button mat-button matSuffix mat-icon-button aria-label="DownVote" id=d-{{item.source}} class=DownVote (click)="vote(i, item, 'ignore')">
    <mat-icon>thumb_down</mat-icon>
    </button>
    </div>
    </div>
</div>

Goal: Ultimately, I'd love to be able to do something as simple as adding box-shadow: 1px -1px 12px 0px #c9c9c9 to the a single mentions element on mouseover and then remove it on mouseout. This is my most recent attempt.

    <div *ngFor = 'let item of feed; let i = index;' [ngClass] = 'state' (mouseover) = "state = 'mentions hover'" (mouseout) = "state = 'mentions'">

Again, it would add to all elements.


Solution

  • You could archive this visual effect by defining a small attribute directive:

        @Directive({
          selector: '[ngHoverClass]'
        })
        export class NgHoverClassDirective {
           @Input(`ngHoverClass`)
           set classesToAply(v: string | string[]){
              this.classes = Array.isArray(v) ? v: v.split(' ');
           }
           private classes: string[] = [];
    
           constructor(private renderer: Renderer2, private element: ElementRef){}
    
           @HostListener('mouseover')
           onHover(){
             this.classes.forEach(c=> this.renderer.addClass(this.element.nativeElement, c));
           }
    
           @HostListener('mouseleave')
           onLeave(){
             this.classes.forEach(c=> this.renderer.removeClass(this.element.nativeElement, c));
           }
        }
    

    After making it available for consume, you could use it in a component as follows:

    <div *ngFor = 'let item of feed; let i = index;' ngHoverClass='hover' class="mentions">