shaelex
shaelex

Reputation: 261

Angular5 ngrx/store changing a value of array

I would like to increment an ID but simply I have no idea how to do it with a @ngrx/store.

My default state:

const defaultState: UserState = {
    currentId: 1,
    users: [
        {
            id: 1,
            username: 'admin',
            password: 'admin'
        },
        {
            id: 2,
            username: 'admin2',
            password: 'admin2'
        },
        {
            id: 3,
            username: 'admin3',
            password: 'admin3'
        }
    ]
};

And for example:

case UserActions.EDIT_CURRENTID:
            return newState(state, {currentId: action.payload});

is working fine, but I want to do something like:

case UserActions.INCREMENT_ID:
                return newState(state, {users[0].id: users[0].id + 1});

and this one is not working.

Can you please give me some advices how to handle this case?

Upvotes: 1

Views: 3905

Answers (2)

pascalpuetz
pascalpuetz

Reputation: 5428

You should change your case to the following:

switch(action.type) {
    case UserActions.INCREMENT_ID:
        return {
           ...state,
           users: [
              { 
                 ...state.users[0],
                 id: state.users[0].id + 1
              },
              ...state.users.filter((_, index) => index > 0)
           ]
        }
}

In @ngrx it is a best practice to use immutable data structures. The old state should never be modified and the objects inside the old state should not be modified as well. This approach creates a new state object and only a new object for the changed user while using the old objects for all other users. If you're not sure there is a list of users then you can expand the example by following:

switch(action.type) {
    case UserActions.INCREMENT_ID:
        return state.users && state.users.length > 0 
           ? {
                ...state,
                users: [
                   { 
                      ...state.users[0],
                      id: state.users[0].id + 1
                   },
                   ...state.users.filter((_, index) => index > 0)
                ]
             } 
           : state;
}

Of course, you can replace

...state.users.filter((_, index) => index > 0)

with

...state.users.slice(1)

Edit: Alternatively, you could use the map function:

switch(action.type) {
    case UserActions.INCREMENT_ID:
        return state.users && state.users.length > 0 
           ? {
                ...state,
                users: state.users.map((user, index) => index === 0 
                    ? { 
                         ...user, 
                         id: user.id + 1 
                      }
                    : user)
             } 
           : state;
}

Upvotes: 4

alsami
alsami

Reputation: 9845

In your reducer function change the increment case to this

switch (action.type) {
   case UserActions.INCREMENT_ID: {
      const users = state.users;
      if (users && users.length > 0) {
         users[0].id += 1;
      }
      // you could also just return the state because the reference to users stays the same
      return {
         ...state,
         users: users
      }
   }
}

Your first case works because the state knows about the property called currentId.

Upvotes: 0

Related Questions