angularangular-signals

Send a signal with the same value


I have a situation when I need to inform subscribers about a signal's being changed with the same value it currently has. I am using the following example: StackBlitz

Then I change line 58:

this.count.update((c) => c + 1);

to:

this.count.update((c) => c + 0);

and nothing is logged into the Console.

Can a signal emit events with duplicate values?


Solution

  • Disclaimer: The signal is designed to trigger only when the actual value changes. This is because, only when the actual value is changed, the derived state (computed or linkedSignal) even needs to fire, so use the below method with caution, it might not be needed, since unless the value is changed, there is no need for the signal to detect a change.



    I am not sure why you have a separate folder for signals, but since it mentions Angular17, the signal function has a second argument (CreateSignalOptions), which is an object with property equals, this defines when the signal event is considered a change.

    Usually, for primitive types (as in your case number) the actual value has to change for the signal to trigger a change, but you have this property equals, which can be used to manipulate this logic, to fire even when there is no actual change.

    ...
    export class App {
      count = signal<number>(0, {
        equal: (a: number, b: number) => false,
      });
      ...
    

    Full Code:

    import { Component, signal, computed, effect } from '@angular/core';
    import { bootstrapApplication } from '@angular/platform-browser';
    import { TestArraysCmp } from './testing-arrays.component';
    import { TestObjectsCmp } from './testing-objects.component';
    import 'zone.js';
    
    @Component({
      selector: 'app-root',
      standalone: true,
      template: `
        <div>Count: {{ count() }}</div>
        <div>Double: {{ double() }}</div>
    
        <button (click)="inc()">Increase</button>
        <button (click)="reset()">Reset</button>
    
        <br>
        <!-- <test-arrays /> -->
        <!-- <test-objects /> -->
    
      `,
      imports: [TestArraysCmp, TestObjectsCmp],
    })
    export class App {
      count = signal<number>(0, {
        equal: (a: number, b: number) => false,
      });
    
      double = computed(() => this.count() * 2);
    
      countType = computed(() => (this.count() % 2 === 0 ? 'even' : 'odd'));
    
      constructor() {
        effect(() => {
          console.log('Count changed', this.count());
          console.log(this.count(), 'is', this.countType());
        });
      }
    
      inc() {
        this.count.update((c) => c + 0);
      }
    
      reset() {
        this.count.set(0);
      }
    }
    
    bootstrapApplication(App);
    

    Stackblitz Demo