Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Reusable Components & Directives: Deep Dive
Search
Manfred Steyer
PRO
October 27, 2022
Programming
430
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Reusable Components & Directives: Deep Dive
Manfred Steyer
PRO
October 27, 2022
More Decks by Manfred Steyer
See All by Manfred Steyer
Generative UI & AI-Assistants for Your Angular Solutions
manfredsteyer
PRO
1
230
Generative UI & AI-Assistants for Your Angular Solutions
manfredsteyer
PRO
0
120
Nostalgia Meets Technology: Super Mario with TypeScript
manfredsteyer
PRO
0
200
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
240
Strategic Design in the Frontend: Moduliths & Micro Frontends @DDDEurope
manfredsteyer
PRO
0
170
Agentic UI
manfredsteyer
PRO
0
240
Signal Forms: Beyond the Basics @ngBaguette 2026 in Paris
manfredsteyer
PRO
0
300
Agentic UI beyond Chats Architecture Patterns & Open Standards @ngMunich 05/2026
manfredsteyer
PRO
0
250
Agentic AI in the Frontend: Architectures with Open Standards @iJS London 2026
manfredsteyer
PRO
0
180
Other Decks in Programming
See All in Programming
2年かけて Deno に DOMMatrix を実装した話 / How I implemented DOMMatrix in Deno over two years
petamoriken
0
180
はてなアカウント基盤 State of the Union
cockscomb
1
1.3k
自作OSでスライド発表する
uyuki234
1
3.9k
数百円から始めるRuby電子工作
tarosay
0
110
分散システム、なんですぐ死んでしまうん?耐障害性を高めたいあなたのためのレジリエンスパターン入門
mshibuya
7
6.9k
AIエージェントで 変わるAndroid開発環境
takahirom
2
720
What's New in Android 2026
veronikapj
0
210
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
410
Lean は証明の正しさを確認するためだけのツールって思ってませんか?
inoueasei
1
110
PHP に部分適用が来るぞ!……ところで何それ?おいしいの? #phpcon / phpcon-2026
shogogg
0
380
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
16k
琵琶湖の水は止められてもNet--HTTPのリトライは止められない / You might be able to stop the water flow of Lake Biwa but you can't stop Net::HTTP retries
luccafort
PRO
0
450
Featured
See All Featured
Between Models and Reality
mayunak
4
380
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
270
Skip the Path - Find Your Career Trail
mkilby
1
170
My Coaching Mixtape
mlcsv
0
180
How GitHub (no longer) Works
holman
316
150k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Producing Creativity
orderedlist
PRO
348
40k
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.3k
Context Engineering - Making Every Token Count
addyosmani
9
1k
A Soul's Torment
seathinner
6
3.1k
Transcript
@ManfredSteyer
@ManfredSteyer Contents • Interacting with Content • Interacting with View
• Working with Handles • Providers vs. ViewProviders
@ManfredSteyer Contents • Attribute Directives • Templates and View Containers
• Structural Directives
@ManfredSteyer Why is this Intersting? • Reusable Components (Component Libraries)
• Better Understanding for Angular
@ManfredSteyer Manfred Steyer
@ManfredSteyer
@ManfredSteyer Case Study #1: Tabbed Pane
@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>
@ManfredSteyer
@ManfredSteyer
@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
@ManfredSteyer Hooks 1) ngOnChanges 2) ngOnInit 3) ngDoCheck 4) ngAfterContentInit
5) ngAfterContentChecked 6) ngAfterViewInit 7) ngAfterViewChecked 8) ngOnDestroy
@ManfredSteyer Hooks 1) ngOnChanges 2) ngOnInit 3) ngDoCheck 4) ngAfterContentInit
5) ngAfterContentChecked 6) ngAfterViewInit 7) ngAfterViewChecked 8) ngOnDestroy
@ManfredSteyer
@ManfredSteyer
@ManfredSteyer Handles <app-tabbed-pane #pane> […] </app-tabbed-pane> Current Page: {{ pane.currentPage
}}
@ManfredSteyer
@ManfredSteyer
@ManfredSteyer Providers @Component({ providers: [NavigatorService] }) export class TabbedPaneComponent {
[…] }
@ManfredSteyer Providers @Component({ providers: [NavigatorService] // Visible in View and
Content }) export class TabbedPaneComponent { […] }
@ManfredSteyer View Providers @Component({ viewProviders: [NavigatorService] // Visible only in
View }) export class TabbedPaneComponent { […] }
@ManfredSteyer
@ManfredSteyer
@ManfredSteyer
@ManfredSteyer Directives • „Components without Templates“ • Add behavior to
an element • Examples: ngModel, ngClass, ngStyle
@ManfredSteyer Case Study <button appClickWithWarning>Delete</button>
@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'); } }
@ManfredSteyer Calling a Directive <button appClickWithWarning>Delete</button> Host-Element
@ManfredSteyer Bindings @Directive({ selector: '[appClickWithWarning]' }) export class ClickWithWarningDirective implements
OnInit { @Input() warning = 'Are you sure?'; @Output() appClickWithWarning = new EventEmitter(); }
@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'; }
@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 { … } }
@ManfredSteyer Calling the Directive <button (appClickWithWarning)="delete()" message="Sure?">Delete</button>
@ManfredSteyer
@ManfredSteyer
@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
@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); } }
@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); […] } }
@ManfredSteyer Mouse-Events const elm = this.host.nativeElement as HTMLElement; elm.addEventListener('mouseover', ()
=> { […] }); elm.addEventListener('mouseout', () => { […] });
@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
@ManfredSteyer
@ManfredSteyer Passing Parameters to Templates this.viewContainer.createEmbeddedView(this.template, { $implicit: 'Tooltip!', helpLink:
'http://www.google.com' }); Context
@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>
@ManfredSteyer
@ManfredSteyer
@ManfredSteyer
@ManfredSteyer ViewContainer • createEmbeddedView • createComponent
@ManfredSteyer
@ManfredSteyer TemplateOutletDirective Insert Template in Placeholder <div *templateOutlet="tmpl"></div> <ng-template #tmpl>Hallo
Welt!</ng-template>
@ManfredSteyer ComponentOutletDirective Insert Component in Placeholder <div *componentOutlet="FlightSearchComponent"></div>
@ManfredSteyer
@ManfredSteyer ContentChildren • @ContentChildren(MyComponentOrDirective, { read: ElementRef | ViewContainerRef })
• Same for @ContentChild, @ViewChildren, @ViewChild
@ManfredSteyer
@ManfredSteyer
@ManfredSteyer Structural Directive <div *ngFor="let f of flights; index as
i"> <pre>{{i}}: {{ f | json }}</pre> </div> Template Micro Syntax
@ManfredSteyer ngFor Implementation Structural Directive <div *ngFor="let f of flights;
index as i"> <pre>{{i}}: {{ f | json }}</pre> </div> Template
@ManfredSteyer $implicit ngForOf index Structural Directive <div *ngFor="let f of
flights; index as i"> <pre>{{i}}: {{ f | json }}</pre> </div> Template context
@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>
@ManfredSteyer Case Study #2: DataTable
@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>
@ManfredSteyer
@ManfredSteyer
@ManfredSteyer Summary • Attribute Directive with Input, Output, HostBinding, HostListener
• ElementRef, TemplateRef, ViewContrainerRef • *ngComponentOutlet, *ngTemplateOutlet • Struktruelle Direktive: Template + Micro Syntax
@ManfredSteyer
@ManfredSteyer 2 1 3 4
@ManfredSteyer Case Study #3: Formatting/Parsing Dates <input [(ngModel)]="date" appDate name="date">
@ManfredSteyer
@ManfredSteyer Case Study #3a: DateControl <app-date [(ngModel)]="date"></app-date>
@ManfredSteyer