Cracking the Angular Renderer

Chau Tran

twitter.com/@nartc1410

github.com/nartc

What is Angular Renderer?

@Component({
    /* ... */
})
export class SomeComponent {
  constructor(private readonly renderer: Renderer2) {}
}
@Component({
    /* ... */
})
export class SomeComponent {
  @ViewChild('someElement', { static: true }) someElement!: ElementRef<HTMLElement>;
  
  constructor(private readonly renderer: Renderer2) {}
  
  ngOnInit() {
    this.renderer.setAttribute(this.someElement.nativeElement, 'attrName', 'attrValue');
  }
}
@Component({
    /* ... */
})
export class SomeComponent {
  @ViewChild('someElement', { static: true }) someElement!: ElementRef<HTMLElement>;
  
  /* no longer needed 
  constructor(private readonly renderer: Renderer2) {}
  */

  ngOnInit() {
    this.someElement.nativeElement.setAttribute('attrName', 'attrValue')
    /*
    this.renderer.setAttribute(this.someElement.nativeElement, 'attrName', 'attrValue');
    */
  }
}

So ... why?

The example only shows how you would interact with the current Renderer

Have you wondered what provides the current Renderer?

import { bootstrapApplication } from '@angular/platform-browser';
import { platformNativeScript, runNativeScriptAngularApp } from '@nativescript/angular';

https://docs.nativescript.org/tutorial/angular.html

import { platformTerminalDynamic } from 'platform-terminal';

https://github.com/Tibing/platform-terminal

Yeah, Angular is platform agnostic

Platform Browser

Platform Browser

@Component({
    template: `
        <div>This is inside the div</div>
        <app-parent />
    `,
    imports: [ParentComponent],
})
export class AppComponent {
    title = 'ng-renderer';
}

Platform Browser

Component

Template

Platform Browser

Component

Template

Compiler

Platform Browser

Component

Template

Compiler

Template

Instructions

Platform Browser

Component

Template

Compiler

Template

Instructions

Renderer

Platform Browser

Component

Template

Compiler

Template

Instructions

Renderer

Platform

Platform Browser

the bridge between your template and the platform

Component

Template

Compiler

Template

Instructions

Renderer

Platform

Platform Browser

the bridge between Angular Core and the platform

Angular

Core

Renderer

Platform

Platform Browser

class AppComponent {
  constructor() {
    this.title = 'ng-renderer';
  }
}
AppComponent.ɵfac = function AppComponent_Factory(t) {
  return new (t || AppComponent)();
};
AppComponent.ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineComponent"]({
  type: AppComponent,
  selectors: [["app-root"]],
  standalone: true,
  features: [_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵStandaloneFeature"]],
  decls: 3,
  vars: 0,
  template: function AppComponent_Template(rf, ctx) {
    if (rf & 1) {
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementStart"](0, "div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵtext"](1, "This is inside the div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementEnd"]();
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelement"](2, "app-parent");
    }
  },
  dependencies: [_parent_component__WEBPACK_IMPORTED_MODULE_0__.Parent],
  encapsulation: 2
});`

Platform Browser

class AppComponent {
  constructor() {
    this.title = 'ng-renderer';
  }
}
AppComponent.ɵfac = function AppComponent_Factory(t) {
  return new (t || AppComponent)();
};
AppComponent.ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineComponent"]({
  type: AppComponent,
  selectors: [["app-root"]],
  standalone: true,
  features: [_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵStandaloneFeature"]],
  decls: 3,
  vars: 0,
  template: function AppComponent_Template(rf, ctx) {
    if (rf & 1) {
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementStart"](0, "div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵtext"](1, "This is inside the div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementEnd"]();
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelement"](2, "app-parent");
    }
  },
  dependencies: [_parent_component__WEBPACK_IMPORTED_MODULE_0__.Parent],
  encapsulation: 2
});`
@Component({
    template: `
        <div>This is inside the div</div>
        <app-parent />
    `,
    imports: [ParentComponent],
})
export class AppComponent {
    title = 'ng-renderer';
}

Platform Browser

class AppComponent {
  constructor() {
    this.title = 'ng-renderer';
  }
}
AppComponent.ɵfac = function AppComponent_Factory(t) {
  return new (t || AppComponent)();
};
AppComponent.ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineComponent"]({
  type: AppComponent,
  selectors: [["app-root"]],
  standalone: true,
  features: [_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵStandaloneFeature"]],
  decls: 3,
  vars: 0,
  template: function AppComponent_Template(rf, ctx) {
    if (rf & 1) {
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementStart"](0, "div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵtext"](1, "This is inside the div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementEnd"]();
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelement"](2, "app-parent");
    }
  },
  dependencies: [_parent_component__WEBPACK_IMPORTED_MODULE_0__.Parent],
  encapsulation: 2
});`

Platform Browser

class AppComponent {
  constructor() {
    this.title = 'ng-renderer';
  }
}
AppComponent.ɵfac = function AppComponent_Factory(t) {
  return new (t || AppComponent)();
};
AppComponent.ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineComponent"]({
  type: AppComponent,
  selectors: [["app-root"]],
  standalone: true,
  features: [_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵStandaloneFeature"]],
  decls: 3,
  vars: 0,
  template: function AppComponent_Template(rf, ctx) {
    if (rf & 1) {
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementStart"](0, "div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵtext"](1, "This is inside the div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementEnd"]();
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelement"](2, "app-parent");
    }
  },
  dependencies: [_parent_component__WEBPACK_IMPORTED_MODULE_0__.Parent],
  encapsulation: 2
});`

Platform Browser

class AppComponent {
  constructor() {
    this.title = 'ng-renderer';
  }
}
AppComponent.ɵfac = function AppComponent_Factory(t) {
  return new (t || AppComponent)();
};
AppComponent.ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineComponent"]({
  type: AppComponent,
  selectors: [["app-root"]],
  standalone: true,
  features: [_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵStandaloneFeature"]],
  decls: 3,
  vars: 0,
  template: function AppComponent_Template(rf, ctx) {
    if (rf & 1) {
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementStart"](0, "div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵtext"](1, "This is inside the div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementEnd"]();
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelement"](2, "app-parent");
    }
  },
  dependencies: [_parent_component__WEBPACK_IMPORTED_MODULE_0__.Parent],
  encapsulation: 2
});`
function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
    /* ... */
    const renderer = lView[RENDERER];
    const native = (lView[adjustedIndex] = createElementNode(renderer, name, getNamespace$1()));
    /* ... */
    return ɵɵelementStart;
}

/* ... */

function createElementNode(renderer, name, namespace) {
    ngDevMode && ngDevMode.rendererCreateElement++;
    return renderer.createElement(name, namespace);
}

Platform Browser

class AppComponent {
  constructor() {
    this.title = 'ng-renderer';
  }
}
AppComponent.ɵfac = function AppComponent_Factory(t) {
  return new (t || AppComponent)();
};
AppComponent.ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineComponent"]({
  type: AppComponent,
  selectors: [["app-root"]],
  standalone: true,
  features: [_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵStandaloneFeature"]],
  decls: 3,
  vars: 0,
  template: function AppComponent_Template(rf, ctx) {
    if (rf & 1) {
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementStart"](0, "div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵtext"](1, "This is inside the div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementEnd"]();
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelement"](2, "app-parent");
    }
  },
  dependencies: [_parent_component__WEBPACK_IMPORTED_MODULE_0__.Parent],
  encapsulation: 2
});`
function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
    /* ... */
    const renderer = lView[RENDERER];
    const native = (lView[adjustedIndex] = createElementNode(renderer, name, getNamespace$1()));
    /* ... */
    return ɵɵelementStart;
}

/* ... */

function createElementNode(renderer, name, namespace) {
    ngDevMode && ngDevMode.rendererCreateElement++;
    return renderer.createElement(name, namespace);
}

Platform Browser

class AppComponent {
  constructor() {
    this.title = 'ng-renderer';
  }
}
AppComponent.ɵfac = function AppComponent_Factory(t) {
  return new (t || AppComponent)();
};
AppComponent.ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineComponent"]({
  type: AppComponent,
  selectors: [["app-root"]],
  standalone: true,
  features: [_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵStandaloneFeature"]],
  decls: 3,
  vars: 0,
  template: function AppComponent_Template(rf, ctx) {
    if (rf & 1) {
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementStart"](0, "div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵtext"](1, "This is inside the div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementEnd"]();
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelement"](2, "app-parent");
    }
  },
  dependencies: [_parent_component__WEBPACK_IMPORTED_MODULE_0__.Parent],
  encapsulation: 2
});`
function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
    /* ... */
    const renderer = lView[RENDERER];
    const native = (lView[adjustedIndex] = createElementNode(renderer, name, getNamespace$1()));
    /* ... */
    return ɵɵelementStart;
}

/* ... */

function createElementNode(renderer, name, namespace) {
    ngDevMode && ngDevMode.rendererCreateElement++;
    return renderer.createElement(name, namespace);
}

Platform Browser

class AppComponent {
  constructor() {
    this.title = 'ng-renderer';
  }
}
AppComponent.ɵfac = function AppComponent_Factory(t) {
  return new (t || AppComponent)();
};
AppComponent.ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineComponent"]({
  type: AppComponent,
  selectors: [["app-root"]],
  standalone: true,
  features: [_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵStandaloneFeature"]],
  decls: 3,
  vars: 0,
  template: function AppComponent_Template(rf, ctx) {
    if (rf & 1) {
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementStart"](0, "div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵtext"](1, "This is inside the div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementEnd"]();
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelement"](2, "app-parent");
    }
  },
  dependencies: [_parent_component__WEBPACK_IMPORTED_MODULE_0__.Parent],
  encapsulation: 2
});`
function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
    /* ... */
    const renderer = lView[RENDERER];
    const native = (lView[adjustedIndex] = createElementNode(renderer, name, getNamespace$1()));
    /* ... */
    return ɵɵelementStart;
}

/* ... */

function createElementNode(renderer, name, namespace) {
    ngDevMode && ngDevMode.rendererCreateElement++;
    return renderer.createElement(name, namespace);
}

Platform Browser

class AppComponent {
  constructor() {
    this.title = 'ng-renderer';
  }
}
AppComponent.ɵfac = function AppComponent_Factory(t) {
  return new (t || AppComponent)();
};
AppComponent.ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineComponent"]({
  type: AppComponent,
  selectors: [["app-root"]],
  standalone: true,
  features: [_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵStandaloneFeature"]],
  decls: 3,
  vars: 0,
  template: function AppComponent_Template(rf, ctx) {
    if (rf & 1) {
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementStart"](0, "div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵtext"](1, "This is inside the div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementEnd"]();
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelement"](2, "app-parent");
    }
  },
  dependencies: [_parent_component__WEBPACK_IMPORTED_MODULE_0__.Parent],
  encapsulation: 2
});`
function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
    /* ... */
    const renderer = lView[RENDERER];
    const native = (lView[adjustedIndex] = createElementNode(renderer, name, getNamespace$1()));
    /* ... */
    return ɵɵelementStart;
}

/* ... */

function createElementNode(renderer, name, namespace) {
    ngDevMode && ngDevMode.rendererCreateElement++;
    return renderer.createElement(name, namespace);
}

Platform Browser

class AppComponent {
  constructor() {
    this.title = 'ng-renderer';
  }
}
AppComponent.ɵfac = function AppComponent_Factory(t) {
  return new (t || AppComponent)();
};
AppComponent.ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineComponent"]({
  type: AppComponent,
  selectors: [["app-root"]],
  standalone: true,
  features: [_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵStandaloneFeature"]],
  decls: 3,
  vars: 0,
  template: function AppComponent_Template(rf, ctx) {
    if (rf & 1) {
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementStart"](0, "div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵtext"](1, "This is inside the div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementEnd"]();
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelement"](2, "app-parent");
    }
  },
  dependencies: [_parent_component__WEBPACK_IMPORTED_MODULE_0__.Parent],
  encapsulation: 2
});`
function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
    /* ... */
    const renderer = lView[RENDERER];
    const native = (lView[adjustedIndex] = createElementNode(renderer, name, getNamespace$1()));
    /* ... */
    return ɵɵelementStart;
}

/* ... */

function createElementNode(renderer, name, namespace) {
    ngDevMode && ngDevMode.rendererCreateElement++;
    // feels similar? document.createElement('div') anyone?
    return renderer.createElement(name, namespace);
}

Platform Browser

class AppComponent {
  constructor() {
    this.title = 'ng-renderer';
  }
}
AppComponent.ɵfac = function AppComponent_Factory(t) {
  return new (t || AppComponent)();
};
AppComponent.ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineComponent"]({
  type: AppComponent,
  selectors: [["app-root"]],
  standalone: true,
  features: [_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵStandaloneFeature"]],
  decls: 3,
  vars: 0,
  template: function AppComponent_Template(rf, ctx) {
    if (rf & 1) {
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementStart"](0, "div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵtext"](1, "This is inside the div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementEnd"]();
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelement"](2, "app-parent");
    }
  },
  dependencies: [_parent_component__WEBPACK_IMPORTED_MODULE_0__.Parent],
  encapsulation: 2
});`
function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
    /* ... */
    const renderer = lView[RENDERER];
    const native = (lView[adjustedIndex] = createElementNode(renderer, name, getNamespace$1()));
    /* ... */
    return ɵɵelementStart;
}

/* ... */

function createElementNode(renderer, name, namespace) {
    ngDevMode && ngDevMode.rendererCreateElement++;
    return renderer.createElement(name, namespace);
}

Platform Browser

class AppComponent {
  constructor() {
    this.title = 'ng-renderer';
  }
}
AppComponent.ɵfac = function AppComponent_Factory(t) {
  return new (t || AppComponent)();
};
AppComponent.ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineComponent"]({
  type: AppComponent,
  selectors: [["app-root"]],
  standalone: true,
  features: [_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵStandaloneFeature"]],
  decls: 3,
  vars: 0,
  template: function AppComponent_Template(rf, ctx) {
    if (rf & 1) {
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementStart"](0, "div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵtext"](1, "This is inside the div");
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelementEnd"]();
      _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵelement"](2, "app-parent");
    }
  },
  dependencies: [_parent_component__WEBPACK_IMPORTED_MODULE_0__.Parent],
  encapsulation: 2
});`

Platform Browser

Platform Browser

Property Binding: [property]="expr"

Platform Browser

Property Binding: [property]="expr"

Attribute Binding: attrName="static-value"

Platform Browser

Property Binding: [property]="expr"

Attribute Binding: attrName="static-value"

Event Binding: (eventName)="handler()"

Platform Browser

<div [id]="title" title="my-title" (click)="onClick()">This is inside the div</div>

Platform Browser

AppComponent.ɵcmp = /*@__PURE__*/ _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵdefineComponent']({
    /* ... */
    consts: [['title', 'my-title', 3, 'id']],
    template: function AppComponent_Template(rf, ctx) {
        if (rf & 1) {
            /* ... */
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵelementStart'](0, 'div', 0);
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵlistener'](
                'click',
                function AppComponent_Template_div_click_0_listener() {
                    return ctx.onClick();
                }
            );
            /* ... */
        }
        if (rf & 2) {
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵproperty']('id', ctx.title);
        }
    },
    /* ... */
});

Platform Browser

AppComponent.ɵcmp = /*@__PURE__*/ _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵdefineComponent']({
    /* ... */
    consts: [['title', 'my-title', 3, 'id']],
    template: function AppComponent_Template(rf, ctx) {
        if (rf & 1) {
            /* ... */
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵelementStart'](0, 'div', 0);
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵlistener'](
                'click',
                function AppComponent_Template_div_click_0_listener() {
                    return ctx.onClick();
                }
            );
            /* ... */
        }
        if (rf & 2) {
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵproperty']('id', ctx.title);
        }
    },
    /* ... */
});
<div [id]="title" title="my-title" (click)="onClick()">This is inside the div</div>

Platform Browser

AppComponent.ɵcmp = /*@__PURE__*/ _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵdefineComponent']({
    /* ... */
    consts: [['title', 'my-title', 3, 'id']],
    template: function AppComponent_Template(rf, ctx) {
        if (rf & 1) {
            /* ... */
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵelementStart'](0, 'div', 0);
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵlistener'](
                'click',
                function AppComponent_Template_div_click_0_listener() {
                    return ctx.onClick();
                }
            );
            /* ... */
        }
        if (rf & 2) {
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵproperty']('id', ctx.title);
        }
    },
    /* ... */
});
<div [id]="title" title="my-title" (click)="onClick()">This is inside the div</div>

Platform Browser

AppComponent.ɵcmp = /*@__PURE__*/ _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵdefineComponent']({
    /* ... */
    consts: [['title', 'my-title', 3, 'id']],
    template: function AppComponent_Template(rf, ctx) {
        if (rf & 1) {
            /* ... */
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵelementStart'](0, 'div', 0);
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵlistener'](
                'click',
                function AppComponent_Template_div_click_0_listener() {
                    return ctx.onClick();
                }
            );
            /* ... */
        }
        if (rf & 2) {
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵproperty']('id', ctx.title);
        }
    },
    /* ... */
});
<div [id]="title" title="my-title" (click)="onClick()">This is inside the div</div>

Platform Browser

AppComponent.ɵcmp = /*@__PURE__*/ _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵdefineComponent']({
    /* ... */
    consts: [['title', 'my-title', 3, 'id']],
    template: function AppComponent_Template(rf, ctx) {
        if (rf & 1) {
            /* ... */
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵelementStart'](0, 'div', 0);
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵlistener'](
                'click',
                function AppComponent_Template_div_click_0_listener() {
                    return ctx.onClick();
                }
            );
            /* ... */
        }
        if (rf & 2) {
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵproperty']('id', ctx.title);
        }
    },
    /* ... */
});
<div [id]="title" title="my-title" (click)="onClick()">This is inside the div</div>

Platform Browser

AppComponent.ɵcmp = /*@__PURE__*/ _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵdefineComponent']({
    /* ... */
    consts: [['title', 'my-title', 3, 'id']],
    template: function AppComponent_Template(rf, ctx) {
        if (rf & 1) {
            /* ... */
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵelementStart'](0, 'div', 0);
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵlistener'](
                'click',
                function AppComponent_Template_div_click_0_listener() {
                    return ctx.onClick();
                }
            );
            /* ... */
        }
        if (rf & 2) {
            _angular_core__WEBPACK_IMPORTED_MODULE_1__['ɵɵproperty']('id', ctx.title);
        }
    },
    /* ... */
});
<div [id]="title" title="my-title" (click)="onClick()">This is inside the div</div>
export declare abstract class Renderer2 {
    abstract get data(): {
        [key: string]: any;
    };
    abstract destroy(): void;
    abstract createElement(name: string, namespace?: string | null): any;
    abstract createComment(value: string): any;
    abstract createText(value: string): any;
    destroyNode: ((node: any) => void) | null;
    abstract appendChild(parent: any, newChild: any): void;
    abstract insertBefore(parent: any, newChild: any, refChild: any, isMove?: boolean): void;
    abstract removeChild(parent: any, oldChild: any, isHostElement?: boolean): void;
    abstract selectRootElement(selectorOrNode: string | any, preserveContent?: boolean): any;
    abstract parentNode(node: any): any;
    abstract nextSibling(node: any): any;
    abstract setAttribute(el: any, name: string, value: string, namespace?: string | null): void;
    abstract removeAttribute(el: any, name: string, namespace?: string | null): void;
    abstract addClass(el: any, name: string): void;
    abstract removeClass(el: any, name: string): void;
    abstract setStyle(el: any, style: string, value: any, flags?: RendererStyleFlags2): void;
    abstract removeStyle(el: any, style: string, flags?: RendererStyleFlags2): void;
    abstract setProperty(el: any, name: string, value: any): void;
    abstract setValue(node: any, value: string): void;
    abstract listen(
        target: 'window' | 'document' | 'body' | any,
        eventName: string,
        callback: (event: any) => boolean | void
    ): () => void;
}

Create a Custom Renderer

Create a Custom Renderer

Create a Custom Renderer

RendererFactory2

Create a Custom Renderer

RendererFactory2

Renderer2

+

Create a Custom Renderer

Demo

Dec 2022

Jan 2023

Thank you

Angular v17 

(upto 17.3)

output()

input()

queries

model()

browserUrl

https://github.com/angular/angular/issues/17004

GuardResult & MaybeAsync

TypeScript 5.4

https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/

https://github.com/angular/angular/releases

Angular Three Renderer

By Chau Tran

Angular Three Renderer

  • 532