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

Angular Architectures with Signals

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Angular Architectures with Signals

Avatar for Manfred Steyer

Manfred Steyer PRO

November 08, 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>, }); readonly flights = this.state.flights; readonly from = this.state.from; […] }
  8. @ManfredSteyer @Injectable({ providedIn: 'root' }) export class FlightBookingFacade { […]

    readonly 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() );