angulartypescriptangular-signals

We need to nest Angular Signals inside another Signal for objects and arrays?


I've made a set of interfaces which describes JSON data. Then I used classes to compose the same data but as Angular Signals:

// TToSignal.ts
import { WritableSignal } from '@angular/core';

export type TToSignal<T> = {
  [k in keyof T]: WritableSignal<T[k]>;
};
// CDataItem.ts
import { IDataItem } from '../interfaces';
import { TToSignal } from '../types';

export class CDataItem implements TToSignal<IDataItem> {
  prop1: signal<string>('');
  prop2: signal<number>(0);

  constructor(init: Partial<IDataItem>) {
    if (!init) return;

    if (init.prop1) this.prop1.set(init.prop1);
    if (init.prop2) this.prop2.set(init.prop2);
  }
}
// CDataProfile.ts
import { IDataProfile } from '../interfaces';
import { TToSignal } from '../types';

export class CDataProfile implements TToSignal<IDataProfile> {
  prop1: signal<string>('');
  prop2: signal<number>(0);

  constructor(init: Partial<IDataProfile>) {
    if (!init) return;

    if (init.prop1) this.prop1.set(init.prop1);
    if (init.prop2) this.prop2.set(init.prop2);
  }
}
// CData.ts
import { CDataProfile, CDataItem } from '../classes';
import { IData } from '../interfaces';
import { TField, TToSignal } from '../types';

export class CData implements TToSignal<IData> {
  name: signal<string>('');
  items: signal<CDataItem[]>([]);
  profile: signal<CDataProfile>(new CDataProfile());

  constructor(init: Partial<IData>) {
    if (!init) return;

    if (init.name) this.name.set(init.name);
    if (init.items) this.items.set(init.items);
    if (init.profile) this.profile.set(init.profile);
  }
}

The data is more complex than this example and I'm wondering: which are the best practices, or how can I approach my data profiling with Signals, considering the use of it inside forms, to interact with it?

Am I overthinking the use of Angular Signals?


Solution

  • Yes, just use a normal data object and set that value to a single signal.

    The signals implementation of Angular forms is not yet released, so whatever code you write to make the data object work with forms could be potential rework (Note: [(ngModel)] works great with signals, just not with the entire form as signal).

    You can use a signal to achieve reactivity and to compute asynchronous (rxResource, httpResource or resource) or synchronous (computed or linkedSignal) derived state from the original signal.

    Currently the entire object can be a signal, then we can use set or update (Preferred) to notify the signal changes.

    Then we can compute derived state when the source signal changes.

    cDataS = signal({ ... });
    ...
    
    ...
    onButtonClick() {
      this.cDataS.update((cDataS: any) => {
        // update gives access to previous state.
        cDataS.profile.push({ ... });
        // after doing the manipulations create a new memory reference for the signal
        // so that the change is detected and the state is recalculated.
        return { ...cDataS }; // shallow copy ->  creates new memory reference.
      });
    }