-
Notifications
You must be signed in to change notification settings - Fork 27.1k
Angular 17 - Mutable signals are not supported #52735
Copy link
Copy link
Closed
Labels
P3An issue that is relevant to core functions, but does not impede progress. Important, but not urgentAn issue that is relevant to core functions, but does not impede progress. Important, but not urgentarea: coreIssues related to the framework runtimeIssues related to the framework runtimecross-cutting: signalsopen for contributionsAn issue that is suitable for a community contributor (based on its complexity/scope).An issue that is suitable for a community contributor (based on its complexity/scope).
Milestone
Description
I noticed that a computed signal does not always fire when one of the dependencies has updated. Let me give a quick example:
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, RouterOutlet],
template: '
<ul>
@for(person of filteredPersons(); track person.name) {
<li>
{{ person.name }} has {{ person.money }} dollars
</li>
}
</ul>
<button (click)="previousPage()">Previous Page</button>
<button (click)="nextPage()">Next Page</button>
<small>Page {{ pagingState().page }} of {{ totalPages() }}</small>
',
styles: [],
})
export class AppComponent {
private persons = this.personService.persons;
filteredPersons = computed(() => {
console.log('One of the dependents has changed :D')
const persons = this.persons();
const pagingState = this.pagingState();
const amountToSkip = (pagingState.page - 1) * pagingState.pageSize;
return persons?.slice(amountToSkip, amountToSkip + pagingState.pageSize);;
})
pagingState = signal({
page: 1,
pageSize: 5
})
totalPages = computed(() => Math.ceil(this.persons()?.length / this.pagingState().pageSize));
constructor(private personService: PersonService) {}
nextPage(): void {
this.pagingState.update((state) => {
if (state.page < this.totalPages()) state.page += 1
return { ...state}; // Cant return state directly since it wont pickup the change whyy????
})
}
previousPage(): void {
this.pagingState.update((state) => {
if (state.page > 1) state.page -= 1
return { ...state}; // Cant return state directly since it wont pickup the change whyy????
})
}
}`
Service
` private _persons = signal<Person[]>(undefined);
get persons() {
return this._persons.asReadonly();
}
hasLoaded = computed(() => this.persons() !== undefined);
constructor() {
this.refresh();
}
getAll(): Observable<Person[]> {
return of([
{
name: 'Alice',
money: 150,
},
{
name: 'Bob',
money: 280,
},
{
name: 'Carol',
money: 210,
},
{
name: 'David',
money: 320,
},
{
name: 'Eva',
money: 180,
},
{
name: 'Frank',
money: 270,
},
{
name: 'Grace',
money: 190,
},
{
name: 'Helen',
money: 230,
}
]).pipe(delay(500))
}
refresh(): void {
this._persons.set(undefined);
this.getAll().subscribe((persons) => {
this._persons.set(persons);
});
}```
Whenever I press one of the page change buttons the pagingState gets updated with the new page value. The correct state is displayed in html but for some reason the computed signal filteredPersons doesnt get triggered. Apparantly it does not see the change which I would have expected. Returning a shallow copy of the state in nextPage and previousPage solves this. If this is expected behavior it would seem really counterintuitive.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
P3An issue that is relevant to core functions, but does not impede progress. Important, but not urgentAn issue that is relevant to core functions, but does not impede progress. Important, but not urgentarea: coreIssues related to the framework runtimeIssues related to the framework runtimecross-cutting: signalsopen for contributionsAn issue that is suitable for a community contributor (based on its complexity/scope).An issue that is suitable for a community contributor (based on its complexity/scope).