I want to run an action just once when a condition changes (to true
), e.g.
areAllDetailsLoaded() => run a function
I was thinking to code it as a Signal like
areAllDetailsLoaded=signal(false);
and using it as
effect( () => {
if (areAllDetailsLoaded()) {
storage().getDetails() ....... run code
The problem I'm facing is that obviously the Signal storage
is also taken into account and anytime the storage()
changes the code runs. Which is not something I want. After areAllDetailsLoaded
is changed to true
the code should run only once.
Honestly I'm running out of ideas. Or perhaps my understanding of Angular Signals is not good enough. Therefore a boiler template pattern would be appreciated - perfered with Signals.
I found some very nice observations.
Only the signal reads at the top level are triggering the effect, not sure if it's by design.
The effect returns a reference, with a destroy property to destroy the effect and make sure the signal runs only once.
Full code:
import { Component, effect, signal } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
@Component({
selector: 'app-root',
standalone: true,
template: `
<button (click)="areAllDetailsLoaded.set(true)">areAllDetailsLoaded set true</button>
`,
})
export class App {
areAllDetailsLoaded = signal(false);
storage = signal(false);
name = 'Angular';
constructor() {
const effectRef = effect(() => {
console.log('effect runs');
// const storage1 = this.storage(); // un comment this to see the effect running for each change of storage
if (this.areAllDetailsLoaded()) {
const storage = this.storage();
console.log('code runs');
effectRef?.destroy();
}
});
}
ngOnInit() {
setInterval(() => {
this.storage.set(!this.storage());
console.log('interval', this.storage());
}, 1000);
}
}
bootstrapApplication(App);