Why do these two functions #workingUpdate and #brokenUpdate behave differently? I actually would expect both functions to fail since the ElementRef does not exist while the constructor is called.
@Component({
selector: 'test-app',
standalone: true,
imports: [CommonModule, ReactiveFormsModule],
template: `
<button (click)="addOne()">count+</button><br/>
count: {{count()}}<br/>
output1: <span #output1></span><br/>
output2: <span #output2></span><br/>
`,
})
export class App {
count = signal(0);
@ViewChild('output1') output1!: ElementRef;
@ViewChild('output2') output2!: ElementRef;
#workingUpdate = () => {
const c = this.count();
this.output1.nativeElement.innerHTML = c;
};
#brokenUpdate = () => {
this.output2.nativeElement.innerHTML = this.count();
};
constructor() {
effect(this.#workingUpdate);
effect(this.#brokenUpdate);
}
addOne() {
this.count.update((c) => c + 1);
}
}
I created a simple Example. I originaly ran into this problem calling a update interface of a third party component. I use the #workingUpdate stucture to fix my problem, but now im not sure if i've just hidden the actual problem.
To answer the specific question, from the docs:
Your example is very interesting.
It does work if I add
console.log()
and read the signal there.Almost looks like it isn't correctly registering the signal for the effect in the
#brokenUpdate
case?UPDATE: I got an answer on this from the Angular team.
Basically, the
brokenUpdate
case doesn't ever register the signal since it throws an exception the first time. So it is never getting re-run when the signal changes.The
workingUpdate
case registers the signal before throwing the error. So it is re-run when the signal changes.One way to fix it is to make the element refs static so they are there when the effects run. Something like this: