Search code examples
angularngxs

ngxs state change for nested child


I'm trying to update a nested child in my state but always end up with an error saying 'cannot assign to read only property'. This is probably due the fact I'm working with immutable state. But how can I change that nested child then?

Here is the code:

@Action(UpdatePortalLogo)
updatePortalLogo(
    ctx: StateContext<PortalStateModel>,
    { logo }: UpdatePortalLogo
) {
    const state = ctx.getState();
    let portal = state.portals.find((portal) => portal.id === state.portalId);
    portal.style.logo = logo; //-> this is the line where it fails

    ctx.setState(
        patch({
            portals: updateItem<Portal>(p => p.id === ctx.getState().portalId,
                portal)
        }));
}

My state model looks like this:

 export interface PortalStateModel {
       portals: Portal[];
       portalId: string;
       loaded: boolean;
       loading: boolean;
    }

Do I need to work with sub states for this to work?


Solution

  • This is because NGXS uses deepFreeze in the development mode. You can check it up by:

    console.log(Object.isFrozen(portal));
    

    You can turn it off by setting developmentMode to false when importing root module:

    NgxsModule.forRoot([], { developmentMode: false })
    

    But you wouldn't want to do this as "freezing" prevents you of doing unpredictable mutations.

    Destructing is your weapon:

    const portal = { ...state.portals.find((portal) => portal.id === state.portalId) };
    

    Also the updateItem operator can take a function as the second argument where you can update your object. As a result the code becomes more declarative:

    ctx.setState(
      patch({
        portals: updateItem(
          portal => portal.id === state.portalId,
          portal => {
            const newPortal = { ...portal };
            newPortal.style.logo = logo;
            return newPortal;
          }
        )
      })
    );