All files / injectables renderer.ts

78.57% Statements 11/14
50% Branches 2/4
75% Functions 3/4
76.92% Lines 10/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 891x                                                                             1x 3x             3x                             4x                   1x 1x   1x 1x 1x                      
import { Injectable, ChangeDetectorRef } from '@angular/core';
 
/**
 * Service that optimizes change detection calls by ensuring that `detectChanges()`
 * is only executed once per execution cycle, even if `update()` is called multiple times.
 *
 * This service is useful for preventing unnecessary re-rendering of Angular components,
 * improving performance and efficiency.
 *
 * @example
 * // Providing ViewRenderer in a Component
 * import { Component, ChangeDetectorRef } from '@angular/core';
 * import { ViewRenderer } from '../services/view-renderer.service';
 *
 * @Component({
 *   selector: 'app-example',
 *   template: `<button (click)="increment()">Increment</button><p>{{ counter }}</p>`,
 *   providers: [
 *     {
 *       provide: ViewRenderer,
 *       useFactory: (cdRef: ChangeDetectorRef) => new ViewRenderer(cdRef),
 *       deps: [ChangeDetectorRef]
 *     }
 *   ]
 * })
 * export class ExampleComponent {
 *   counter = 0;
 *
 *   constructor(private renderer: ViewRenderer) {} // Inject ViewRenderer with ChangeDetectorRef
 *
 *   increment() {
 *     for (let i = 0; i < 10; i++) {
 *       this.counter++;
 *       this.renderer.markForCheck(); // `detectChanges()` will only be called once per cycle
 *     }
 *   }
 * }
 */
@Injectable()
export class ViewRenderer {
    private _scheduled = false;
 
    /**
     * Constructs the `ViewRenderer` service and injects the `ChangeDetectorRef`.
     *
     * @param change - The `ChangeDetectorRef` instance for managing change detection in Angular.
     */
    constructor(private change: ChangeDetectorRef) {
        // nothing to do
    }
 
    /**
     * Returns the `ChangeDetectorRef` instance associated with this service.
     *
     * @returns The `ChangeDetectorRef` instance used for change detection.
     *
     * @example
     * // Accessing ChangeDetectorRef from ViewRenderer
     * const cdRef = this.renderer.cdref;
     * cdRef.markForCheck();
     */
    get cdref(): ChangeDetectorRef{
        return this.change;
    }
 
    /**
     * Schedules a change detection cycle. If called multiple times in the same execution cycle,
     * it ensures that `detectChanges()` is only executed once.
     *
     * This method improves performance by avoiding redundant calls to `detectChanges()`.
     */
    markForCheck(force = false): void {
        if (!this._scheduled) {
            this._scheduled = true;
    
            if (force){
                this.change.detectChanges();
                this._scheduled = false;
            }
            else E{ // delay change detection
                Promise.resolve().then(() => {
                    this.change.detectChanges();
                    this._scheduled = false;
                });    
            }
        }
    }
}