Home > Net >  Can't get mutator logic to correctly add the proper amount of items into a cart
Can't get mutator logic to correctly add the proper amount of items into a cart

Time:01-30

I'm trying to make an add to cart function that first checks if the item being added is already in the cart. If it's in the cart, update its quantity property. If not in the cart, add the entire object to the cart. I think my problem is I'm getting the logic wrong inside my "ADD_ITEM_TO_CART" mutator function.


This is my store with some console.logs() from when I click "addToCart()"

state: {
    checkoutCart: [],
  },


actions: {
  cartAdd({ commit }, payload) {
      commit("ADD_ITEM_TO_CART", payload);
   },
 },

mutations: {
    ADD_ITEM_TO_CART(state, payload) {
          //CONSOLE.LOG()'s
          console.log("state.checkoutCart[0]", state.checkoutCart[0]);
          // eslint-disable-next-line
          console.log("state.checkoutCart[0].item", state.checkoutCart.item);
          console.log("state.checkoutCart", state.checkoutCart);

          //IF ITEM ALREADY IN checkoutCart, UPDATE IT'S QUANTITY
          if (state.checkoutCart.includes(payload.item)) {
            state.checkoutCart.quantity  = payload.quantity;
            console.log("Item already in cart");
          } 
          //IF ITEM NOT IN checkoutCart, UPDATE THE QUANTITY PROPERTY AND ADD ITEM TO CART
          else {
            payload.item.quantity = payload.quantity;
            state.checkoutCart.push(payload);
          }

https://i.imgur.com/rjOOljN.png

I thought this code would work, but it ALWAYS executes the ELSE condition and adds to cart like the

if (state.checkoutCart.includes(payload.item))

isn't being recognized or working at all.


https://i.imgur.com/LLB790Z.png

VueX devtools shows the same thing. An "item" object inside an object inside an array.

I also tried:

ADD_ITEM_TO_CART(state, payload) {
  console.log("add_item_to_cart"); <---ONLY PART THAT SHOWS UP IN CONSOLE.LOG() WHEN EXECUTED

  //LOOP THROUGH ALL ARRAY ENTRIES TO GAIN ACCESS TO state.checkoutCart.item 
  for (let i = 0; i < state.checkoutCart.length; i  ) {
    console.log("i=", i);
    console.log("state.checkoutCart.item", state.checkoutCart.item);

    //IF ITEM ALREADY IN checkoutCart, UPDATE IT'S QUANTITY
    if (state.checkoutCart[i].item.includes(payload.item)) {
      state.checkoutCart.quantity  = payload.quantity;
      console.log("Item already in cart");
      return;
    }; 
  }
  //IF ITEM NOT IN checkoutCart, UPDATE THE QUANTITY PROPERTY AND ADD ITEM TO CART 
  payload.item.quantity = payload.quantity;
  state.checkoutCart.push(payload);
},

because I figured I needed to loop through all the array entries. BUT the for loop doesn't even run, and with this code nothing gets added to the cart at all.


I can't figure out what I'm doing wrong here. Can somebody help? Is my syntax wrong? Or is my logic? Am I accessing the arrays/objects incorrectly? How do I write the "ADD_ITEM_TO_CART" mutator function correctly? I've literally spent all day on this and my brain is shutting down.

EDIT:

https://i.imgur.com/bkU8YSo.png

PAYLOAD

         <div v-for="item in items">  <--ACTUALLY PROP FROM PARENT COMPONENT BUT SAME IDEA
          <p>
            Qty
            <select v-model="quantity">
              <option value="1">1</option>
              <option value="2">2</option>
              <option value="3">3</option>
            </select>
          </p>
          <p>
            <button type="button" @click="addToCart()">
              Add to Cart
            </button>
          </p>
        </div>

let quantity = ref("1");
const addToCart = () => {
  console.log("addToCart Running");
  store.dispatch("cartAdd", { item: item.value, quantity: quantity.value });
};

CodePudding user response:

That is because your if condition is not checking for what you think.

Array.prototype.includes checks if a value is in the array but there are two cases:

  • the value is a primary type (string, number, boolean, ...). It compares by value.
  • the value is an object. Then it compares by reference.

So here, you are checking if the reference of your item object is already included in the array. But it's not, since it's a new object.


Solution: check if there is an object with the same values, not reference.

You can use the some method, and you have to write a condition that checks if two items are equals.

Here is an example if your items have an id:

if (state.checkoutCart.some(item => item.id === payload.item.id))

CodePudding user response:

The problem is indeed inside ADD_ITEM_TO_CART mutation.

As Kapcash has pointed out, two objects having the same properties and the same values are not the same.

In other words, .includes() checks for identity, not equality. To better understand this, consider this example:

const a = { foo: 'bar' }
const b = [{ foo: 'bar' }]
const c = [a]
const d = [{ ...a }]

console.log(b.includes(a)) // false
console.log(c.includes(a)) // true
console.log(d.includes(a)) // false

To get past this, use Kapcash's answer.
I'll just mention the standard way of dealing with this problem is using unique identifiers on objects (e.g: uuids).


Once you fix the above, it's still not going to work, because you'll run into the following problem: inside the if you're attempting to alter state.checkoutCart's quantity. And an array does not have a quantity property.

The proper logic to achieve the desired functionality is (assuming the unique identifier on checkoutCart members is item._id, from the pictures you posted):

ADD_ITEM_TO_CART(state, payload) {
  // find the index of a cart element having same `item._id` value as the payload
  const index = state.checkoutCart.findIndex(
    (el) => el.item._id === payload.item._id
  )
  if (index > -1) {
    // if the index is higher than `-1`, an element was found
    // create a copy, update its quantity and then 
    // replace the original element with the copy
    const copy = { ...state.checkoutChart[index] }
    copy.quantity  = payload.quantity
    state.checkoutCart.splice(index, 1, copy)
  } else {
    // no element found, add payload to `checkoutCart`
    state.checkoutCart.push(payload)
  }
}

Side note: None of your items should contain a quantity property. That's the cart's responsibility, not the item's. By adding it to the item you end up with two sources of truth which you'd need to keep in sync. You don't want this type of problem.

  • Related