0
votes

I have an issue with a component. I'm managing a task list application. I have an observable array that I cycle in a wrapper with async pipe, and a child component "Todo component" that as an input called "Todo", and an attribute "showDetails" that's a Boolean used for UI toggle and it's initialized as false. This is the structure:

<div *ngFor="let todo of todo$">
  <app-todo [todo]="todo"></app-todo>
</div>

Inside the todo-component template I have a button where I toggle the Boolean value. There is also a function "toggle" that dispatchs an action that updates the ngrx state of the todo. When I dispatch the action and reducer updates the state, the component is totally reloaded and also if showDetails is setted to true it comes back to false because component is reloaded.

This is the reducer function that updates the state

  on(Toggle, (state, action) =>
        state.map(i => (i.id === action.id ? { ...i, todo: !i.todo } : i))
  )
           

This is an example on stackblitz: Demo

I would that my showDetails value remaining the same also with the state change...

1

1 Answers

2
votes

the reason is you don't provide the trackBy function to ngFor. And, as a result, every time the array is updated, ngFor creates new views and destroys the old ones. to fix that provide trackByFn so ngFor would know what element is being updated.

// app.component.ts
trackById(idx, {id}) {
  return id;
} 
<div *ngFor="let todo of todos$ | async; trackBy: trackById" ...