Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Creating Custom Structural Directives in Angular

Avatar for Ashnita Ashnita
October 24, 2019

Creating Custom Structural Directives in Angular

This talk is about creating custom structural directives to implement the logic to create embedded views. It gives a brief introduction to directives, views and dynamic views, and TemplateRef, view containers and ViewContainerRef, naming input properties, how structural directives pass context to embedded views which they access using template input variables. It also talks about the syntactic sugar provided by the asterisk and the microsyntax in the string passed to structural directives when using the asterisk syntax.

Avatar for Ashnita

Ashnita

October 24, 2019

More Decks by Ashnita

Other Decks in Programming

Transcript

  1. What we will cover 1. Directives 2. Views and dynamic

    views 3. Steps to create custom structural directives a. <ng-template> and TemplateRef b. View containers and ViewContainerRef 4. Magic behind the asterisk 5. Microsyntax
  2. Component View (html) Styles (css) Data & methods (ts) Attribute

    Directives Appearance and behaviour Structural Directives View structure
  3. Changes host element’s appearance or behaviour Any element @HostBinding @HostListener

    @Input @Output Attribute Directive Structural Directive Changes view structure <ng-template> asterisk * syntax TemplateRef ViewContainerRef @Input Context object
  4. @Component({ selector: ‘app-book-list’, template: ` <app-book-detail appHover *ngfor=”let book of

    books$ | async”> </app-book-detail>` }) export class BookListComponent {}
  5. Directives examples Angular Application Angular Libraries HTML elements <app-root> <app-book-list>

    <router-outlet> <ng-template>, <ng-container>, <ng-content> HTML attributes appCarousel appHighlight ngFor, ngIf, ngTemplateOutlet, ngSwitchCase routerLink, ngClass, ngStyle, ngForm
  6. “A view is the smallest grouping of display elements that

    can be created and destroyed together. “ - angular.io
  7. 1. Rendering a view based on some reusable logic: *appHasRole,

    *appHasPermision, *appHasFeature 2. Only implement the functionality, allowing the user to define the view: *appCarousel 3. Declare variables *appLet Examples of when to create structural directives
  8. <div *appLet=”{ obs1: obs1$ | async, obs2: obs2$ | async

    } as data”> {{ data.obs1.prop }} {{ data.obs2.prop }} </div>
  9. ViewContainerRef API Methods: createComponent() createEmbeddedView() insert(viewRef, index) clear() detach(index) move(viewRef,

    index) remove(index) get(index) indexOf(viewRef) Properties: element length injector _embeddedViews Create Manipulate Query
  10. ViewContainerRef element _embeddedViews createComponent() createEmbeddedView() move() remove() ... View container

    <my-comp> <h1>Component View</h1> <!----> </my-comp> <div>User with admin role can see this</div>
  11. @Directive({ selector: '[appHasRole]' }) export class HasRoleDirective { @Input() appHasRole;

    @Input() appHasRoleElse: TemplateRef<HasRoleContext>; @Input() appHasRoleThen: TemplateRef<HasRoleContext>; } Input properties
  12. Input property name = directive attribute name @Component({ template: `

    <ng-template [appHasRole]=”’admin’”> <div>User with admin role can see this</div> </ng-template> `})
  13. @Component({ template: ` <div *appHasRole=”’customer’”; else elseRef> User with customer

    role can see this. </div> <ng-template #elseRef>Render if user doesn’t have role</ng-template> `})
  14. export class HasRoleDirective { @Input() appHasRole; context = { $implicit:

    this.appHasRole, role: this.appHasRole, } } Context object
  15. export class CarouselDirective { @Input() appCarouselFrom; index = 0; context

    = { $implicit: this.appCarouselFrom[index], control: { next: () => this.next(), previous: () => this.previous() } } } Context object
  16. Template input variables access context properties <ng-template let-book let-next=”next” let-prev=”previous”>

    <h1>...}<h1> <ng-template> context = { $implicit: currentItem, next: () => this.next(), previous: () => this.previous() }
  17. Create type for context object abstract class TemplateRef<C> { abstract

    createEmbeddedView(context: C): EmbeddedViewRef<C> }
  18. ngFor export class NgForOfContext<T> { constructor( public $implicit: T, public

    ngForOf: NgIterable<T>, public index: number, public count: number) {} get first(): boolean { return this.index === 0; } get last(): boolean { return this.index === this.count - 1; } get even(): boolean { return this.index % 2 === 0; } get odd(): boolean { return !this.even; } }
  19. export class HasRoleDirective { @Input() appHasRole; constructor(private roleService: RoleService) {}

    ngOnInit() { this.sub = this.roleService.user$ .pipe(filter(roles => roles.includes(this.appHasRole))) .subscribe(() => { this.vcr.clear(); this.vcr.createEmbeddedView(this.templateRef) }) } }
  20. Component template @Component({ template: ` <div *ngFor=” let book of

    books; index as i” class=”” appHighlight> <p>Embedded view with book details</p> </div> `})
  21. Component template @Component({ template: ` <div *ngFor=” let book of

    books; index as i” class=”” appHighlight> <p>Embedded view with book details</p> </div> `})
  22. *dir=“let var1 key1:expr1; ctxProp as var2; key2: expr2” *ngFor=”let item

    of items; index as i; trackby: f” Input property declarations and property bindings
  23. “let localVar1” “let localVar2=ctxProp1” “ctxProp2 as localVar3” Template input variable

    declarations let-localVar1=”$implicit” let-localVar2=”ctxProp1” let-localVar3=”ctxProp2”
  24. Resources 1. https://angular.io/guide/structural-directives 2. https://itnext.io/angular-structural-directives-b54ea21b39a7 3. https://netbasal.com/building-a-simple-carousel-component-with-angular-3a94092b7080 4. https://netbasal.com/understanding-angular-structural-directives-659acd0f67e 5.

    https://stackoverflow.com/questions/56062311/what-is-the-exact-grammar-for-angulars-structural-dir ectives 6. https://stackoverflow.com/questions/46616334/where-does-angular-4-define-as-local-var-behavior-f or-ngif 7. https://stackoverflow.com/questions/38752744/angular2-how-is-ngfor-expanded