angularmodelsignalsangular-signalsangular18

Signal will not updated in differ <div> node in same html


I have a simple code in Angular 18 as to understand the change mechanismus: By the timeintervall the signal A() value will changed and triggert the computed W. The W reference will be pass to signal E. In the result, E will be updated within the same div and only if W is visiable.

app.component.ts:

import {Component, computed, signal} from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterLink, RouterOutlet],
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss'
})
export class AppComponent {
  title = 'AngularTestV18';
public T: boolean=true

  public A=signal(0);
  public W = computed(this.A);
  E=signal(this.W)

  private i=1
  private t=setInterval(() => {this.A.set((this.i++));
    console.log(this.W());
  }, 100);
}

and app.component.html

<div>
App-Template!
<br>
  <button (click)="T=!T">W visible</button>
<br>
<div>
  <div>
    Injected W:  {{W()}}
    Signal E: {{E()}}
    @if (T) {   Signal E: {{E()}} }

  </div>
  <div>
     @if (T) {  Injected W:  {{W()}}  }
    Signal E: {{E()}}
  </div>
</div>
</div>

Why is there a differ between the update strategy of signal E as

App-Template! W/E visible Injected W: 337 Signal E: [Computed: 337] Signal E: [Computed: 109] - updated if W visiable Injected W: 337 Signal E: [Computed: 0] - never updated

?


Solution

  • You should define signal E as a computed(this.W) since the computed will trigger to changes of signal W. In your question E signal was defined as a signal of a signal (E=signal(this.W)), which does not work, since signal E is calculated by W, so its a computed signal.

    Eventhough we remove the signal W from the DOM/HTML, does not mean the signal will not trigger the change detection, it will fire for all signals linked to W.

    import { Component, signal, computed } from '@angular/core';
    import { bootstrapApplication } from '@angular/platform-browser';
    
    @Component({
      selector: 'app-root',
      standalone: true,
      template: `
        <div>
        App-Template!
        <br>
          <button (click)="T=!T">W visible</button>
        <br>
        <div>
          <div>
            Injected W:  {{W()}}
            Signal E: {{E()}}
            @if (T) {   Signal E: {{E()}} }
    
          </div>
          <div>
            @if (T) {  Injected W:  {{W()}}  }
            Signal E: {{E()}}
          </div>
        </div>
        </div>
      `,
    })
    export class App {
      title = 'AngularTestV18';
      public T: boolean = true;
    
      public A = signal(0);
      public W = computed(this.A);
      E = computed(this.W);
    
      private i = 1;
      private t = setInterval(() => {
        this.A.set(this.i++);
        console.log(this.W());
      }, 100);
    }
    
    bootstrapApplication(App);
    

    Stackblitz Demo