I have a setup in my Angular project where I’m using signals to manage state. Specifically, I have a projectSignal that holds a Project object which can contain an array of Task objects, and each Task can have a Permission object.
Here’s the current setup:
projectSignal: Signal<Project | undefined> = toSignal(this.store.select(selectActiveProject));
permission: Signal<Permission | undefined> = computed(() => this.projectSignal()?.tasks?.[0]?.permission);
And the corresponding HTML:
<app-permission [permissionsSelected]="permission"></app-permission>
}
This works well for conditionally rendering the component based on the existence of the permission object.
I also have an Output and I’m listening to this output in the constructor:
constructor(@Inject(MAT_DIALOG_DATA) public data: DialogData, private store: Store<AppState>) {
effect(() => {
this.updatePermission().output.subscribe((test: any) => {
// Logic to handle the event
});
});
}
Now, I would like to modify the projectSignal and consequently the permission signal when a certain event occurs (for example, a button click). How can I update the projectSignal in response to an event (in effect()) , so that the permission signal reflects the new state?
Additional Information:
This question follows up on a previous one : Best Practices for Nested Optional Checks in Angular Template with Signals
The goal is to change the permission value when a user interacts with the UI, such as clicking a button.
What i tried
- Change Signal to WritableSignal
- change the computed signal to a new one build in the effect
- I’m unable tu use update() or set() from angular signals…
Any guidance or best practices on how to achieve this would be greatly appreciated! Thank you!
This code looks like a memory leak, since for each effect trigger, the subscriptions are not destroyed and will keep on piling, causing the application to crash with sufficient items. You need to remove the effect and just subscribe to changes. Or unsubscribe the previous subscription then create a new one. Let me know if you need that code snippet
constructor(@Inject(MAT_DIALOG_DATA) public data: DialogData, private store: Store<AppState>) {
// effect(() => {
this.updatePermission().output.subscribe((test: any) => {
// Logic to handle the event
});
// });
}
When you click any button, trigger an event, which updates the root store selectActiveProject
this will trigger the signal (projectSignal
) to change, which will trigger the compute for permission
. Since the code is not shared unable to analyze this question more than this.
Another way is to just use a signal store, instead of a conventional store.
2
I found a solution,
I initialized an attribute Permission in the component and implemented it on the effect
projectSignal: Signal<Project | undefined> = toSignal(this.store.select(selectActiveProject));
permission!: Permission;
childRef: Signal<ChildRef> = viewChild.required(ChildRef)
And in the effect in the constructor
constructor(@Inject(MAT_DIALOG_DATA) public data: DialogData) {
effect(() => {
this.permission= this.projectSignal()?.tasks?.[0]?.permission
this.childRef().output.subscribe((output: any) => {
if (output && this.permission) {
this.permission= {
...this.permission,
statut : true
};
}
})
})
It works well, i can update the attribute when i want