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

Reusable Components & Directives: Deep Dive

Reusable Components & Directives: Deep Dive

Manfred Steyer
PRO

October 27, 2022
Tweet

More Decks by Manfred Steyer

Other Decks in Programming

Transcript

  1. @ManfredSteyer

  2. @ManfredSteyer Contents • Interacting with Content • Interacting with View

    • Working with Handles • Providers vs. ViewProviders
  3. @ManfredSteyer Contents • Attribute Directives • Templates and View Containers

    • Structural Directives
  4. @ManfredSteyer Why is this Intersting? • Reusable Components (Component Libraries)

    • Better Understanding for Angular
  5. @ManfredSteyer Manfred Steyer

  6. @ManfredSteyer

  7. @ManfredSteyer Case Study #1: Tabbed Pane

  8. @ManfredSteyer Tabbed Pane <app-tabbed-pane> <app-tab title="Upcoming Flights"> <p>No upcoming flights!</p>

    </app-tab> <app-tab title="Operated Flights"> <p>No operated flights!</p> </app-tab> <app-tab title="Cancelled Flights"> <p>No cancelled flights!</p> </app-tab> </app-tabbed-pane>
  9. @ManfredSteyer

  10. @ManfredSteyer

  11. @ManfredSteyer View vs. Content @Component({ selector: 'tab', template: ` <div

    *ngIf="visible"> <h1>{{title}}</h1> <div> <ng-content></ng-content> </div> </div> ` }) export class TabComponent { @Input() title: string; visible: boolean = true; } Content <tab title="Booked"> Sample Text ... </tab> View
  12. @ManfredSteyer Hooks 1) ngOnChanges 2) ngOnInit 3) ngDoCheck 4) ngAfterContentInit

    5) ngAfterContentChecked 6) ngAfterViewInit 7) ngAfterViewChecked 8) ngOnDestroy
  13. @ManfredSteyer Hooks 1) ngOnChanges 2) ngOnInit 3) ngDoCheck 4) ngAfterContentInit

    5) ngAfterContentChecked 6) ngAfterViewInit 7) ngAfterViewChecked 8) ngOnDestroy
  14. @ManfredSteyer

  15. @ManfredSteyer

  16. @ManfredSteyer Handles <app-tabbed-pane #pane> […] </app-tabbed-pane> Current Page: {{ pane.currentPage

    }}
  17. @ManfredSteyer

  18. @ManfredSteyer

  19. @ManfredSteyer Providers @Component({ providers: [NavigatorService] }) export class TabbedPaneComponent {

    […] }
  20. @ManfredSteyer Providers @Component({ providers: [NavigatorService] // Visible in View and

    Content }) export class TabbedPaneComponent { […] }
  21. @ManfredSteyer View Providers @Component({ viewProviders: [NavigatorService] // Visible only in

    View }) export class TabbedPaneComponent { […] }
  22. @ManfredSteyer

  23. @ManfredSteyer

  24. @ManfredSteyer

  25. @ManfredSteyer Directives • „Components without Templates“ • Add behavior to

    an element • Examples: ngModel, ngClass, ngStyle
  26. @ManfredSteyer Case Study <button appClickWithWarning>Delete</button>

  27. @ManfredSteyer Simple Example @Directive({ selector: '[appClickWithWarning]' }) export class ClickWithWarningDirective

    implements OnInit { constructor(private elementRef: ElementRef) { } ngOnInit(): void { this.elementRef .nativeElement.setAttribute('class', 'btn btn-danger'); } }
  28. @ManfredSteyer Calling a Directive <button appClickWithWarning>Delete</button> Host-Element

  29. @ManfredSteyer Bindings @Directive({ selector: '[appClickWithWarning]' }) export class ClickWithWarningDirective implements

    OnInit { @Input() warning = 'Are you sure?'; @Output() appClickWithWarning = new EventEmitter(); }
  30. @ManfredSteyer Bindings @Directive({ selector: '[appClickWithWarning]' }) export class ClickWithWarningDirective implements

    OnInit { @Input() warning = 'Are you sure?'; @Output() appClickWithWarning = new EventEmitter(); @HostBinding('class') classBinding = 'btn btn-danger'; }
  31. @ManfredSteyer Bindings @Directive({ selector: '[appClickWithWarning]' }) export class ClickWithWarningDirective implements

    OnInit { @Input() warning = 'Are you sure?'; @Output() appClickWithWarning = new EventEmitter(); @HostBinding('class') classBinding = 'btn btn-danger'; @HostListener('click', ['$event']) handleClick($event: MouseEvent): void { … } }
  32. @ManfredSteyer Calling the Directive <button (appClickWithWarning)="delete()" message="Sure?">Delete</button>

  33. @ManfredSteyer

  34. @ManfredSteyer

  35. @ManfredSteyer Example: Tooltip <input [appTooltip]="tmpl"> <ng-template #tmpl> <h3>2 Tips for

    Success</h3> <ol> <li>Don't tell everything!</li> </ol> </ng-template> ViewContainer
  36. @ManfredSteyer Implementation @Directive({ selector: '[appTooltip]' }) export class TooltipDirective implements

    OnInit { @Input('appTooltip') template: TemplateRef<unknown>; constructor(private host: ElementRef, private viewContainer: ViewContainerRef) { } ngOnInit(): void { this.viewContainer.createEmbeddedView(this.template); } }
  37. @ManfredSteyer Implementation export class TooltipDirective implements OnInit { private viewRef:

    EmbeddedViewRef<unknown>; @Input('appTooltip') template: TemplateRef<unknown>; constructor( private host: ElementRef, private viewContainer: ViewContainerRef) { } ngOnInit(): void { this.viewRef = this.viewContainer.createEmbeddedView(this.template); […] } }
  38. @ManfredSteyer Mouse-Events const elm = this.host.nativeElement as HTMLElement; elm.addEventListener('mouseover', ()

    => { […] }); elm.addEventListener('mouseout', () => { […] });
  39. @ManfredSteyer Iterate over Projected Root Nodes this.viewRef.rootNodes.forEach(nativeElement => { nativeElement.hidden

    = true; }); <input [appTooltip]="tmpl"> <ng-template #tmpl> <h3>2 Tips for Success</h3> <ol> <li>Don't tell everything!</li> </ol> </ng-template> Root Nodes
  40. @ManfredSteyer

  41. @ManfredSteyer Passing Parameters to Templates this.viewContainer.createEmbeddedView(this.template, { $implicit: 'Tooltip!', helpLink:

    'http://www.google.com' }); Context
  42. @ManfredSteyer Using Parameters in Template <ng-template #tmpl let-title let-link="helpLink"> <h3>{{title}}</h3>

    <p> Deletes EVERYTHING! </p> <a [href]="link">More</a> </ng-template>
  43. @ManfredSteyer

  44. @ManfredSteyer

  45. @ManfredSteyer

  46. @ManfredSteyer ViewContainer • createEmbeddedView • createComponent

  47. @ManfredSteyer

  48. @ManfredSteyer TemplateOutletDirective Insert Template in Placeholder <div *templateOutlet="tmpl"></div> <ng-template #tmpl>Hallo

    Welt!</ng-template>
  49. @ManfredSteyer ComponentOutletDirective Insert Component in Placeholder <div *componentOutlet="FlightSearchComponent"></div>

  50. @ManfredSteyer

  51. @ManfredSteyer ContentChildren • @ContentChildren(MyComponentOrDirective, { read: ElementRef | ViewContainerRef })

    • Same for @ContentChild, @ViewChildren, @ViewChild
  52. @ManfredSteyer

  53. @ManfredSteyer

  54. @ManfredSteyer Structural Directive <div *ngFor="let f of flights; index as

    i"> <pre>{{i}}: {{ f | json }}</pre> </div> Template Micro Syntax
  55. @ManfredSteyer ngFor Implementation Structural Directive <div *ngFor="let f of flights;

    index as i"> <pre>{{i}}: {{ f | json }}</pre> </div> Template
  56. @ManfredSteyer $implicit ngForOf index Structural Directive <div *ngFor="let f of

    flights; index as i"> <pre>{{i}}: {{ f | json }}</pre> </div> Template context
  57. @ManfredSteyer Syntax Sugar <div *ngFor="let f of flights; index as

    i"> <pre>{{i}}: {{ f | json }}</pre> </div> <ng-template ngFor let-f [ngForOf]="flights" let-i="index"> <div> <pre>{{i}}: {{ f | json }}</pre> </div> </ng-template>
  58. @ManfredSteyer Case Study #2: DataTable

  59. @ManfredSteyer DataTable <app-data-table [data]="flights"> <div *appTableField="let data as 'id'">{{data}}</div> <div

    *appTableField="let data as 'from'">{{data}}</div> <div *appTableField="let data as 'to'">{{data}}</div> <div *appTableField="let data as 'date'"> {{data | date:'dd.MM.yyyy HH:mm'}} </div> </app-data-table>
  60. @ManfredSteyer

  61. @ManfredSteyer

  62. @ManfredSteyer Summary • Attribute Directive with Input, Output, HostBinding, HostListener

    • ElementRef, TemplateRef, ViewContrainerRef • *ngComponentOutlet, *ngTemplateOutlet • Struktruelle Direktive: Template + Micro Syntax
  63. @ManfredSteyer

  64. @ManfredSteyer 2 1 3 4

  65. @ManfredSteyer Case Study #3: Formatting/Parsing Dates <input [(ngModel)]="date" appDate name="date">

  66. @ManfredSteyer

  67. @ManfredSteyer Case Study #3a: DateControl <app-date [(ngModel)]="date"></app-date>

  68. @ManfredSteyer