'NGXS Update value of deeply nested property

I´m working with Angular and NGXS on a simple application to let users create simple products with tags, but I´m struggling with updating the nested properties.

I have a User model with a Product array.

export interface User {
  id: number;
  name: string;
  products: Product[];
}

And the Product model has an array of tags.

export interface Product {
  id: number;
  name: string;
  tags: Tag[];
}

And the Tag model has also some properties.

export interface Tag {
  id: number;
  name: string;
}

I want to be able to ADD, GET, UPDATE, REMOVE single Products or single Tags.

On the GitHub Documentation of NGXS (https://github.com/ngxs/store/blob/master/docs/recipes/immutability-helpers.md) I found this examples which updates a simgle property in an array:

export interface TrelloStateModel {
  tasks: {
    [taskId: string]: Task;
  };
}

export class TrelloState {
  @Action(UpdateDueDate)
  updateDueDate(ctx: StateContext<TrelloStateModel>, action: UpdateDueDate) {
    ctx.setState(
      patch({
        tasks: patch({
          [action.taskId]: patch({
            dates: patch({
              dueDate: action.dueDate
            })
          })
        })
      })
    );
  }
}

But I simply don´t know how to make this work for my object model. Is there a better alternative to this?



Solution 1:[1]

I'll explain what I'd do to add a single product to the array of a specific user.

First, in your user.action.ts file, create an Add action:

export class AddProduct { 
   static readonly type = [Product] Add product to list
   constructor(public product: Product) {}
}

Then, in your user.state.ts implement the Add action:

@Action(UserActions.AddProduct)
addProduct(ctx: StateContext<User>, action: UserActions.AddProduct) {
   const state = ctx.getState()

   //check whether the product you want to add is already in the list
   if(state.products.find(p => p.id === action.id) {
       //don't try to add a product that is already in the list
   } else {
       ctx.setState(
           patch({
               products: append([action.product])
       )}
     )
   }
}

Both patch and append are state operators and you need to import them from '@ngxs/store/operators'; import { patch, append} from '@ngxs/store/operators';

If you want to update a deep nested object, you may have to use patch within another patch and so on.

Then on your user.page.ts I'd create the product and then call this.store.dispatch(UserActions.AddProduct(product)).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 jiujipsu