4
votes

In angular template I am trying to load rows of a table using ng for. I also have some conditional content in certain columns that loads markup based on the values of other column. (code shown at the end)

The problem I am facing is that even if I am moving mouse on this page , on the browser console I see message "isEligibleForVacDays executed" multiple times. When I say multiple times , It is literally more than 1000 times in 4 seconds just by moving the mouse quickly on the page.

How do I avoid this & making sure it gets executed only once? I am using similar ngif='method-call()' syntax on 5 places. I read that we could use pure pipes & I also tested & it was not executing multiple times.

I would like to know what is the correct way to resolve this issue. Thanks for taking time to read my question.

See below.

Template markup for one row

 <mat-cell class="actions center " *matCellDef="let employeeRow">
     <span  *ngIf="isEligibleForVacDays(employeeRow)"
            class="actionIcon"
            (click)="onReloadClick(employeeRow)"
            matTooltip="Eligible for Vacation Days">
            <i class="fa fa-refresh fa-2x" aria-hidden="true"></i>
                </span>
    </mat-cell>

Function in component typescript file

    isEligibleForVacDays()
{   
    console.log('isEligibleForVacDays executed')
    let isEligibleForVacDays = false;

    some complex logic based on instance variables set on the component

    // finally returning true or false
    return isEligibleForReload;
}
2
You have soething, somewhere, that causes a mouse listener to be added to the table (or the document), and this listener does its job inside the Angular zone, causing a detection change to execute whenever you move the mouse. If it's normal, and doesn't cause any performance/power consumption problem, then just don't care about it. If not, find what it is and fix it.JB Nizet
If all your cells have a matTooltip, every mouseEnter/mouseLeave in every cell will cause such change detections. But once again, if you have 1000 logs in 4 seconds, it means each change detection is very fast (250 CDs per second), and you should not care about it: just remove your console.log().JB Nizet
@JBNizet Thanks for the answer. Is there any better way to cope with this scenario as it is so common that sometimes component could have many ngif(s) with method calls. Is there any inbuilt angular construct to hint Angular that you are executing it unnecessarily & execute it once ?hp8888

2 Answers

1
votes

A pipe is only going to be executed once for every employee, so it is ideal if the condition is not going to change while the component is displayed.

From the angular documentation:

Angular executes a pure pipe only when it detects a pure change to the input value. A pure change is either a change to a primitive input value (String, Number, Boolean, Symbol) or a changed object reference (Date, Array, Function, Object).

The only thing to remember is that if you need the condition to be re evaluated, you'll need to change the object reference (i.e. by using Object.assign or a spread)

-1
votes

A very easy way to solve your problem is change the change detection method of your component to OnPush.

@Component({
  selector: 'app-YOUR-COMPONENT',
  templateUrl: './YOUR-COMPONENT.component.html',
  styleUrls: ['./YOUR-COMPONENT.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})

But, you'll going to have to detect the changes manualy.

constructor( private change: ChangeDetectorRef) {}

isEligibleForVacDays() {
  // do something
  this.change.detectChanges();
}