Search code examples
angularangular-signals

Push in Angular Signals Array


Context:

With Angular 16, we can now use Signals.

But it doesn't seem clear to me how to do a simple push into an array.

The documentation suggests from Angular Signal official doc:

When working with signals that contain objects, it's sometimes useful to mutate that object directly. For example, if the object is an array, you may want to push a new value without replacing the array entirely. To make an internal change like this, use the .mutate method

So it would be for example:

messages = signal<Message[]>([]);

ngOnInit(): void {
   const newMessage = ...
   this.messages.mutate(values => values.push(newMessage));
}

But it seems pretty weird to refer 2 times to the list. The first time with this.messages and the second one with values.

Question:

How can I push an item into a Signal array?


Solution

  • You should be using update (instead of mutate that has been remove in v17). Signal expect to be immutable (if you don't provide a compareFn when creating them).

    messages = signal<Message[]>([]);
    
    ngOnInit(): void {
       const newMessage = ...
       this.messages.update(values => {
          return [...values, newMessage];
       });
    }
    

    To sum up the types we are working with here:

    • message: Signal<Message[]>
    • values: Message[]

    When you call update() you're invoking the method on a Signal. The signal here is the reactive primitive not the value itself.

    You call that value with : messages(). This is signals 101.

    Cf the definition of signals by Angular:

    const SIGNAL = Symbol('SIGNAL');
    
    export type Signal<T> = (() => T)&{
      [SIGNAL]: unknown;
    };
    

    So when you call update, you're actually telling the Signal to update its value. Signal.set() just accepts a value to set so you're changing the reference, while Signal.update() takes a callback to update and you should be returning a new reference.