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
Lightweight Architectures: With Angular's Signa...
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Manfred Steyer
PRO
September 19, 2023
Programming
430
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Lightweight Architectures: With Angular's Signals and Standalone
Manfred Steyer
PRO
September 19, 2023
More Decks by Manfred Steyer
See All by Manfred Steyer
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
28
Strategic Design in the Frontend: Moduliths & Micro Frontends @DDDEurope
manfredsteyer
PRO
0
86
Agentic UI
manfredsteyer
PRO
0
130
Signal Forms: Beyond the Basics @ngBaguette 2026 in Paris
manfredsteyer
PRO
0
230
Agentic UI beyond Chats Architecture Patterns & Open Standards @ngMunich 05/2026
manfredsteyer
PRO
0
220
Agentic AI in the Frontend: Architectures with Open Standards @iJS London 2026
manfredsteyer
PRO
0
140
Agentic AI & UI: Arcitecture, HITL, Emerging Standards
manfredsteyer
PRO
0
170
Agentic UI Requires Standards: AG-UI, A2UI, and MCP Apps Work Together @Angular London
manfredsteyer
PRO
1
96
Signal Forms: Beyond the Basics @ngBelgrade 2026
manfredsteyer
PRO
0
210
Other Decks in Programming
See All in Programming
Skillsは効率化、Agentsは"自分の拡張"——Builder時代のエージェント編成(CC Night 2026)
wemra
1
120
AIとASP.NET Coreで雑Webアプリを作った話
mayuki
0
490
TAKTでAI駆動開発の品質を設計する
j5ik2o
6
1.1k
CSC307 Lecture 17
javiergs
PRO
0
320
Inside Stream API
skrb
1
680
CLIであることを活かしたGitHub Copilot CLI活用術 / GitHub Copilot CLI Pro Tips & Tricks
nao_mk2
1
1.2k
TSKaigi Night Talks 2026_TypeScriptでサプライチェーンの整合性を型に閉じ込める
geekplus_tech
0
330
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
230
Make SRE Operations Easier with Azure SRE Agent
kkamegawa
0
5.2k
Dataformのリポジトリを立ち上げるときにまずやること / dataform-day0-2026
snhryt
0
130
Claspは野良GASの夢をみるか
takter00
0
180
肥大化するレガシーコードに立ち向かうためのインターフェース分離と依存の逆転 / JJUG CCC 2026 Spring
hirokunimaeta
0
530
Featured
See All Featured
Heart Work Chapter 1 - Part 1
lfama
PRO
7
36k
Art, The Web, and Tiny UX
lynnandtonic
304
22k
YesSQL, Process and Tooling at Scale
rocio
174
15k
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
200
Facilitating Awesome Meetings
lara
57
7k
The Cult of Friendly URLs
andyhume
79
6.9k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
600
From π to Pie charts
rasagy
0
200
Designing Powerful Visuals for Engaging Learning
tmiket
1
410
Optimising Largest Contentful Paint
csswizardry
37
3.7k
Darren the Foodie - Storyboard
khoart
PRO
3
3.4k
AI: The stuff that nobody shows you
jnunemaker
PRO
8
700
Transcript
@ManfredSteyer Lightweight Architectures With Angular's Signals and Standalone ManfredSteyer
@ManfredSteyer
@ManfredSteyer
@ManfredSteyer
@ManfredSteyer
@ManfredSteyer
@ManfredSteyer Manfred Steyer
@ManfredSteyer
@ManfredSteyer NgModules + EcmaScript Modules import { NgModule } from
'@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; […] @NgModule({ imports: [BrowserModule, OtherModule], declarations: [AppComponent, OtherComponent, OtherDirective], providers: [], bootstrap: [AppComponent], }) export class AppModule {} TypeScript Modules Angular Modules
@ManfredSteyer @Component({ standalone: true, imports: [ […], FlightCardComponent, CityPipe, CityValidator,
], selector: 'flight-search', templateUrl: '…' }) export class FlightSearchComponent { […] }
@ManfredSteyer
@ManfredSteyer Small and Medium Apps: Folder per Feature
@ManfredSteyer Your Public APIs: Barrels // index.ts == Public API
export * from './flight-booking.routes';
@ManfredSteyer Medium and Large Apps: Folder per Domain
@ManfredSteyer Restricting Access b/w Domains, etc. on a library basis
@ManfredSteyer Restricting Access on a folder basis Tech Lead Rainer
Hahnekamp, AngularArchitects @softarc/eslint-plugin-sheriff
@ManfredSteyer
@ManfredSteyer Free eBook ANGULARarchitects.io/standalone Standalone Components Download here:
@ManfredSteyer
@ManfredSteyer Zone.js: Monkey Patching After Event Handler: Inform Angular CD
Checks Components all components (default) or selected ones (OnPush)
@ManfredSteyer Zone.js: Magic Zone.js: ~100K Cannot patch async/await coarse grained
CD e.g. Components are always checked as a whole, even if only a tiny fraction changed
@ManfredSteyer Signals!
@ManfredSteyer Signals!
@ManfredSteyer Signal as Producer 4711 Consumer read set notify 4712
@ManfredSteyer flights: Flight[] = []; const flights = await this.flightService.findAsPromise(from,
to); this.flights = flights; <div *ngFor="let f of flights"> <flight-card [item]="f" /> </div>
@ManfredSteyer flights = signal<Flight[]>([]); const flights = await this.flightService.findAsPromise(from, to);
this.flights.set(flights); <div *ngFor="let f of flights()"> <flight-card [item]="f" /> </div>
@ManfredSteyer
@ManfredSteyer
@ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]
private _flights = signal<Flight[]>([]); readonly flights = this._flights.asReadonly(); async load(from: string, to: string) { const flights = await […]; this._flights.set(flights); } }
@ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]
private _flights = signal<Flight[]>([]); readonly flights = this._flights.asReadonly(); async load(from: string, to: string) { const flights = await […]; this._flights.set(flights); } }
@ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]
private _flights = signal<Flight[]>([]); readonly flights = this._flights.asReadonly(); private _from = signal('Hamburg'); readonly from = this._from.asReadonly(); private _to = signal('Graz'); readonly to = this._to.asReadonly(); […] }
@ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]
private state = signal({ from: 'Hamburg', to: 'Graz', flights: [] as Flight[], […] }, { equal }); […] }
@ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]
private state = signal({ from: 'Hamburg', to: 'Graz', flights: [] as Flight[], […] }, { equal }); flights = computed(() => this.state().flights, { equal }); from = computed(() => this.state().from, { equal }); […] }
@ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]
private state = signal({ from: 'Hamburg', to: 'Graz', flights: [] as Flight[], […] }, { equal }); flights = computed(() => this.state().flights, { equal }); from = computed(() => this.state().from, { equal }); […] } const equal = (a,b) => a === b
@ManfredSteyer
@ManfredSteyer select(selector) selectSignal(selector)
@ManfredSteyer
@ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { private
state = signalState({ from: 'Paris', to: 'London', flights: [] as Flight[], basket: {} as Record<number, boolean>, }); flights = this.state.flights; from = this.state.from; […] }
@ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]
selected = selectSignal( () => this.flights().filter((f) => this.basket()[f.id]); […] }
@ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]
selected2 = selectSignal( this.flights, this.basket, (flights, basket) => flights.filter((f) => basket[f.id]) ); […] }
@ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]
updateCriteria(from: string, to: string): void { this.state.$update({ from, to }); } […] }
@ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]
updateCriteria(from: string, to: string): void { this.state.$update(state => ({ ...state, from, to })); } […] }
@ManfredSteyer
@ManfredSteyer export const FlightBookingStore = signalStore( { providedIn: 'root' },
[…] );
@ManfredSteyer export const FlightBookingStore = signalStore( { providedIn: 'root' },
withState({ from: 'Paris', to: 'London', […] }), […] );
@ManfredSteyer export const FlightBookingStore = signalStore( { providedIn: 'root' },
withState({ from: 'Paris', to: 'London', […] }), withSignals(([…]) => ({ […] })), withMethods(([…]) => ({ })), withHooks({ […] }), withCallState() );
@ManfredSteyer
@ManfredSteyer const BooksStore = signalStore( withEntities<Book>({ collection: 'book' }), withEntities<Author>({
collection: 'author' }) );
@ManfredSteyer const BooksStore = signalStore( withLoadEntities<Book>(BookService), withLoadEntities<Author>(AuthorService), );
@ManfredSteyer
@ManfredSteyer
@ManfredSteyer d Slides & Examples Remote Company Workshops and Consulting
http://angulararchitects.io