Skip to content

Latest commit

 

History

History
123 lines (107 loc) · 2.7 KB

AngularSignalExample.md

File metadata and controls

123 lines (107 loc) · 2.7 KB

object-recipes: Angular + signals example

This example was created on Angular v20.3.0.

/* src/state/person.ts  */

import { entity, Recipe, Shape } from 'object-recipes';
import { signal } from '@angular/core';

export const personEntity = entity({
  name: 'John Doe',
  age: 20,
  address: {
    street: 'Some street 99',
    zip: 1000,
    country: 'Some country',
  },
});

export const setNameAgeAction =
  (
    values: Partial<Pick<Shape<typeof personEntity>, 'name' | 'age'>>
  ): Recipe<typeof personEntity> =>
  (entity) =>
    entity.set(values);

export const setAddressAction =
  (
    values: Partial<Shape<typeof personEntity>['address']>
  ): Recipe<typeof personEntity> =>
  (entity) =>
    entity.set({
      address: { ...entity.get().address, ...values },
    });

export const personSignal = signal(personEntity.getSafe());
/* src/person.ts */

/* eslint-disable import/no-deprecated */
import { Component, computed } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { recipeSafe } from 'object-recipes';
import {
  personSignal,
  setNameAgeAction,
  setAddressAction,
} from '../store/person';

@Component({
  selector: 'person-signal-component',
  imports: [CommonModule, FormsModule],
  template: `
    <h1>Person: Signal</h1>
    Hello! {{ name() }}
    <br />
    {{ address() | json }}
    <br /><br />
    Name:
    <input
      type="text"
      [ngModel]="name()"
      (ngModelChange)="setName($event)"
    /><br />
    Age:
    <input
      type="number"
      [ngModel]="age()"
      (ngModelChange)="setAge($event)"
    /><br />
    <br />
    <br />
    <b>Address</b>
    <br />
    Street:
    <input
      type="text"
      [ngModel]="address().street"
      (ngModelChange)="setAddress({ street: $event })"
    /><br />
    Zip:
    <input
      type="text"
      [ngModel]="address().zip"
      (ngModelChange)="setAddress({ zip: $event })"
    /><br />
    Country:
    <input
      type="text"
      [ngModel]="address().country"
      (ngModelChange)="setAddress({ country: $event })"
    /><br />
  `,
})
export class PersonSignalComponent {
  private person = personSignal;

  name = computed(() => this.person().name);

  age = computed(() => {
    const age = this.person().age;
    return isNaN(age) ? '' : age.toString();
  });

  address = computed(() => this.person().address);

  setName(name: string) {
    this.person.update(recipeSafe(setNameAgeAction({ name })));
  }

  setAge(age: string) {
    this.person.update(recipeSafe(setNameAgeAction({ age: parseInt(age) })));
  }

  setAddress(address: Parameters<typeof setAddressAction>[0]) {
    this.person.update(recipeSafe(setAddressAction(address)));
  }
}