简体   繁体   中英

Update ngrx state in nested object Angular

I would be able to update an object nested in another object in my application but i got some problems. Let's assume that the entity that I want to update is something like this:

{
  {
  "id": 0,
  "name": "Yellow Car",
  "details": {
    "engine": {},
    "ownerInfo": {
      "name": "Luke",
      "lastName": "Cage",
      "email": "l.cage@hisemail.blabla"
    },
  },
  "created": "2018-01-17",
  "lastUpdate": "2020-09-03",
}

I can easily update some part of this entity in this way:

let car: Car = {
   ...car,
   ...this.form.value
};

let carUpdate: Update<Car> = {
  id: car.id,
  changes: car
};

this.store.dispatch(carUpdated({carUpdate}));

But in this way I can only update name, created, lastUpdate and I can't update the nested object details . What happens if I try to edit the detail object now? Nothing i wanna happens.

This is the selector:

export const carUpdated = createAction(
    "[Edit Car] Car Updated",
    props<{carUpdate: Update<Car>}>()
);

The effect:

 saveCar$ = createEffect(
        () => this.actions$
        .pipe(
            ofType(CarActions.carUpdated),
            concatMap(action => this.carService.editCar(
                action.carUpdate.changes,
                action.carUpdate.id
            ))
        ),
        {dispatch: false}
    )

The reducer:

on(CarActions.carUpdated, (state, action) =>
    adapter.updateOne(action.carUpdate, state)),

The service sends to the backend the right data and it's working good without the state management. What I am doing now is retrieve the single carObject in this way in the component in the ngOnInit

car$ = this.store.pipe(
   select(selectCar(id))
)

and the selector is:

export const selectCar = (id) => createSelector(
    selectAllCars,
    (cars: any) => cars.filter((car) => {
        let filteredCar = car.id == id;
        if(filteredCar) {
            return car;
        }
    }).map(car => car)
);

and then after my edit I can use the dispatch to confirm my edit

this.store.dispatch(carUpdated({carUpdate}));

but as I said if I try to update the details object i have this

let car: Car = {
       ...car, // the entire car object
       ...this.form.value // only the details
    };
    
    let carUpdate: Update<Car> = {
      id: car.id,
      changes: car //the details are mixed with the car object and not inside the object itself
    };

something like this:

{
  "id": 0,
  "name": "Yellow Car",
  "engine": {},
  "details": {
  },
  "ownerInfo": {
    "name": "Luke",
    "lastName": "Cage",
    "email": "l.cage@hisemail.blabla"
  },
  "created": "2018-01-17",
  "lastUpdate": "2020-09-03",
}

Is there an easy way to fix this?

I'll try to provide a general answer which might show techniques on how to update one object with another object.

If in the form, you only have the details as update (update is Partial<Car["details"]> , you can do this:

const update: Partial<Car["details"]> = this.form.value;
const newCar: Car = {
   ...oldCar,
   details: {
      ...oldCar.details,
      ...update
   }

Then there's the possibility that the update is (partial) Car with partial details :

const update: Partial<Car> & { details: Partial<Car["details"]> } = this.form.value;

const newCar: Car = {
   ...oldCar,
   ...update,
   details: {
      ...oldCar.details,
      ...update.details
   }
}

An improbable option is that you have mixed detail and car properties in the update (for whatever reason - you might be doing something wrong). Then you can pick them by hand. Note that this will delete old values if new values are undefined.

const update: Pick<Car, 'name' | 'lastUpdate'> & Pick<Car["details"], 'ownerInfo'> = this.form.value;

const newCar: Car = {
   ...oldCar,
   name: update.name,
   lastUpdate: update.lastUpdate,
   name: update.name
   details: {
      ...oldCar.details,
      ownerInfo: details.ownerInfo
   }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM