Search code examples
angularngformouseentermouseleave

Angular mouse leave not called with *ngFor


The (mouseleave) directive is not working, if it is generated with *ngFor:

@Component({
  selector: 'my-app',
  template: `
  <ng-container *ngFor="let item of hoverdivs; index as i">
      <div style="background-color: grey" (mouseenter)="hoverdivs[i]=true" (mouseleave)="hoverdivs[i]=false">
      <p>Hoverable div #{{i}}</p>
      <p> hover status: {{item}} </p>
    </div>
  </ng-container>


  `,
})
export class App {
  hover:boolean;

  hoverdivs = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]

  constructor() {
  }
}

My working example can be seen here: if you move the mouse fast enough, you can see that some of the divs "stuck" on hovering status.

screenshot after fast mouse movement

Is there a way to force mouseleave call?


Solution

  • That is not problem from mouseenter or mouseleave. It's because render from angular, see this thread.

    So the logic is, when mouseenter to the div (when slow) it actually call twice. You can debug it by function.

    <div style="background-color: grey; height: 80px; margin-bottom: 15px;"
        (mouseenter)="fire($event, i)"
        (mouseleave)="fire($event, i)">
          Hoverable div #{{i}}
          hover status: {{hoverdivss[i]}}
        </div>
    
    fire(e,key) {
        e.stopPropagation();
        console.log(key)
      }
    

    even you put e.stopPropagation(); it won't work cause angular will change hoverdivs and re-render template and eventually trigger mouseenter again. It will call twice.

    here steps:

    1. mouseenter
    2. angular change value to true
    3. trigger position last mouse
    4. because same div trigger again mouseenter

    In your case, you have problem fast mouse moving not change value true to false cause after angular done render, angular not call mouseenter again.

    To solve this problem you should avoid template re-rendering.

    Play DEMO.