Search code examples
angularngforangular-directiveangular-templateangular-signals

Template/view using for directive is not getting updated with signal


I have this code. In debug I can see that WorkersComponent#workers are updated properly. Unfrotunatelly ui is not updated. What's wrong?

@Component({
  selector: 'app-planning-workers',
  templateUrl: './workers.component.html',
  styleUrl: './workers.component.scss',
})
export class WorkersComponent {
  private planningStore = inject(PlanningStore);
  workers: Worker[] = [];

  constructor() {
    effect(() => {
      this.workers = this.planningStore.workers();
    });
  }
}
<div class='people-wrapper'>
  <div class='people-bubble-wrapper'>
    @for (worker of workers; track worker.id) {
      <app-bubble [worker]='worker'></app-bubble>
    }
  </div>
</div>


Solution

  • A signal to be use in the template, should always be called as a function and its better to be used directly instead of using a effect and adding the value to a variable.

    As you are already using inject for the service, change the workers from an array to the same type as the signal and then set the value as this.planningStore.workers (don't need to be in the constructor).

    In the HTML, change the for to @for (worker of workers(); track worker.id) { and you will be using the signals the right way.

    If you need to add some extra code every time the workers array change, use the effect to do some code and then call markForCheck from ChangeDetectorRef if template changes are needed.

    Remember that your trying to use signals with a object (everything that its not a primitive type is a object in its roots) and you should be giving a new instance for the signal to really update.

    Example of adding a new row into your existing array:

    const tempWorkers = this.workers();
    tempWorkers.push(NEW_DATA);
    this.workers.set([...tempWorkers]);
    

    In your WorkersComponent:

    workers = this.planningStore.workers();
    

    In the HTML of WorkersComponent:

    @for (worker of workers(); track worker.id) {
      <app-bubble [worker]='worker'></app-bubble>
    }
    

    I would say to you that is better to aways use changeDetection: ChangeDetectionStrategy.OnPush if your trying to use the maximum from signals and preventing excessive template checking, calling markForCheck when needed.