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

Lightweight Architectures: With Angular's Signals and Standalone

Lightweight Architectures: With Angular's Signals and Standalone

Manfred Steyer

September 19, 2023
Tweet

More Decks by Manfred Steyer

Other Decks in Programming

Transcript

  1. @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
  2. @ManfredSteyer @Component({ standalone: true, imports: [ […], FlightCardComponent, CityPipe, CityValidator,

    ], selector: 'flight-search', templateUrl: '…' }) export class FlightSearchComponent { […] }
  3. @ManfredSteyer Restricting Access on a folder basis Tech Lead Rainer

    Hahnekamp, AngularArchitects @softarc/eslint-plugin-sheriff
  4. @ManfredSteyer Zone.js: Monkey Patching After Event Handler: Inform Angular CD

    Checks Components all components (default) or selected ones (OnPush)
  5. @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
  6. @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>
  7. @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>
  8. @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); } }
  9. @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); } }
  10. @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(); […] }
  11. @ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]

    private state = signal({ from: 'Hamburg', to: 'Graz', flights: [] as Flight[], […] }, { equal }); […] }
  12. @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 }); […] }
  13. @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
  14. @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; […] }
  15. @ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]

    selected = selectSignal( () => this.flights().filter((f) => this.basket()[f.id]); […] }
  16. @ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]

    selected2 = selectSignal( this.flights, this.basket, (flights, basket) => flights.filter((f) => basket[f.id]) ); […] }
  17. @ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]

    updateCriteria(from: string, to: string): void { this.state.$update({ from, to }); } […] }
  18. @ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]

    updateCriteria(from: string, to: string): void { this.state.$update(state => ({ ...state, from, to })); } […] }
  19. @ManfredSteyer export const FlightBookingStore = signalStore( { providedIn: 'root' },

    withState({ from: 'Paris', to: 'London', […] }), […] );
  20. @ManfredSteyer export const FlightBookingStore = signalStore( { providedIn: 'root' },

    withState({ from: 'Paris', to: 'London', […] }), withSignals(([…]) => ({ […] })), withMethods(([…]) => ({ })), withHooks({ […] }), withCallState() );