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

Angular Architectures with Signals

Angular Architectures with Signals

Manfred Steyer

October 24, 2023
Tweet

More Decks by Manfred Steyer

Other Decks in Programming

Transcript

  1. @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>
  2. @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); } }
  3. @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); } }
  4. @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(); […] }
  5. @ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]

    private state = signal({ from: 'Hamburg', to: 'Graz', flights: [] as Flight[], […] }); […] }
  6. @ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]

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

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

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

    updateCriteria(from: string, to: string): void { patchState(this.state, (state) => ({ from, to })); } […] }
  11. @ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]

    updateCriteria(from: string, to: string): void { patchState(this.state, updateRoute(from, to)); } […] } function updateRoute<T>(from: string, to: string) { return (state: T) => ({ from, to }) }
  12. @ManfredSteyer private state = signalState({ filter: { from: 'Paris', to:

    'London', }, flights: [] as Flight[], basket: {} as Record<number, boolean>, }); filter = this.state.filter(); from = this.state.filter.from(); to = this.state.filter.to();
  13. @ManfredSteyer export const FlightBookingStore = signalStore( { providedIn: 'root' },

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

    withState({ from: 'Paris', to: 'London', […] }), withComputed(([…]) => ({ […] })), withMethods(([…]) => ({ })), withHooks({ […] }) );
  15. @ManfredSteyer export const FlightBookingStore = signalStore( […] withMethods((state) => {

    […] return { connectCriteria: rxMethod<Criteria>((c$) => c$.pipe([…])) }; }), […] );
  16. @ManfredSteyer export const FlightBookingStore = signalStore( […] withMethods((state) => {

    […] return { connectCriteria: rxMethod<Criteria>((c$) => c$.pipe([…])) }; }), […] );
  17. @ManfredSteyer export const FlightBookingStore = signalStore( […] withMethods((state) => {

    […] return { connectCriteria: rxMethod<Criteria>((c$) => c$.pipe( filter(c => c.from.length >= 3 && c.to.length >= 3), debounceTime(300), switchMap((c) => flightService.find(c.from, c.to)), tap(flights => patchState(state, { flights })) )) }; }), […] );
  18. @ManfredSteyer export const FlightBookingStore = signalStore( […] withHooks({ onInit({ connectCriteria,

    criteria }) { connectCriteria(criteria); }, }), ); takes: Signal<T>, Observable<T>, T
  19. @ManfredSteyer export const FlightBookingStore = signalStore( { providedIn: 'root' },

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

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