Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

boyjarv's avatar

toggle item in an array

At the moment, when I click on a product, it adds to the array selectedItems and adds onto the totalPrice, I would like to remove from the array selectedItems and minus the price form totalPrice if it's in the array?! please help...

addProduct(product) {
      this.selectedItems.push(product);
      
      console.log("Product: ", product);
      this.totalPrice += product.price;
    },
0 likes
15 replies
tykus's avatar

How does the product object look - is there a unique ID?

boyjarv's avatar

Yes, there is an ID:

productItems: [
        {
          id: 1,
          name: "Identity requirements",
          price: 6.0,
        },
        {
          id: 2,
          name: "Request a quotation",
          price: 3.0,
        },
        {
          id: 3,
          name: "Find products",
          price: 16.0,
        },
    }
]

I tried includes()

if (this.selectedItems.includes(product.id)) {
        this.selectedItems.slice(product);
        this.totalPrice -= product.price;
      } else {
        this.selectedItems.push(product);
        this.totalPrice += product.price;
      }

This doesn't work?!

Sinnbeck's avatar

@boyjarv How about

this.selectedItems = this.selectedItems.filter((p) => p.id !== product.id);
boyjarv's avatar

@Sinnbeck Thanks but that didn't work either:

addProduct(product) {
      if (
        (this.selectedItems = this.selectedItems.filter(
          (p) => p.id !== product.id
        ))
      ) {
        this.selectedItems.slice(product);
        this.totalPrice -= product.price;
      } else {
        this.selectedItems.push(product);
        this.totalPrice += product.price;
      }
    },

it just removed the price and so the total price went to £-3 so didn't even go into the selectedItems array

Sinnbeck's avatar

@boyjarv Ok let me make it more clear

if (this.selectedItems.search((p) => p.id === product.id) !== -1)) {
       this.selectedItems = this.selectedItems.filter((p) => p.id !== product.id);
        this.totalPrice -= product.price;
      } else {
        this.selectedItems.push(product);
        this.totalPrice += product.price;
      }
tykus's avatar

@boyjarv filter is not a good idea if it is possible to have the same product in the selectedProducts multiple times. Use findIndex to get the first index matching the condition

function removeProduct(product) {
   selectedItems.splice(selectedItems.findIndex( item => item.id === product.id ), 1 );
}

Lastly, I would suggest that totalPrice is not changed in the addProduct method, instead a computed property based on the selectedItems data:

let totalPrice = computed(() => selectedItems.reduce((total, product) => total += product.price, 0)
boyjarv's avatar

@tykus

Thanks for how would I add the totalPrice to the created() Vue lifecycle?

here is my code so far:

<template>
  <ul class="flex flex-grow flex-wrap items-list justify-around">
    <li
      v-for="item in items"
      :key="item.id"
      @click.prevent="addProduct(item)"
      class="
        w-1/3
        drop-shadow-lg
        bg-white
        rounded-full
        text-black
        item
        mb-10
        flex flex-row
        items-center
        align-center
        justify-between
        px-6
        hover:cursor-pointer
      "
    >
      <div
        class="
          flex
          h-8
          w-8
          justify-center
          items-center
          rounded-full
          border-purple border-2
        "
      >
        <i class="fa fa-check text-purple"></i>
      </div>
      <span class="text-base text-purple justify-center text-center">{{
        item.name
      }}</span>
      <div class="flex flex-col uppercase text-lightpurple text-xs font-bold">
        Estimate
        <span class="text-sm text-purple font-normal"
          >&pound;&nbsp;{{ item.price.toFixed(2) }}</span
        >
      </div>
    </li>
  </ul>
  <div class="flex flex-row justify-evenly">
    <div>&nbsp;</div>
    <div
      class="
        total-price
        drop-shadow-lg
        bg-white
        rounded-full
        text-black
        item
        mb-10
        flex flex-row
        items-center
        align-center
        justify-between
        px-6
        hover:cursor-pointer
      "
    >
      <div
        class="
          flex
          justify-center
          items-center
          uppercase
          font-bold
          text-base text-purple
        "
      >
        Total
      </div>
      <div class="flex flex-col uppercase text-lightpurple text-xs font-bold">
        <span class="text-xxl text-red font-normal"
          >&pound;&nbsp;{{ this.totalPrice.toFixed(2) }}</span
        >
      </div>
    </div>
    <div>3</div>
  </div>
</template>

<script>
export default {
  name: "ProductItem",
  props: {
    items: {
      typeof: "Array",
    },
  },
  data() {
    return {
      selectedItems: [],
      itemSelected: false,
      totalPrice: 0,
    };
  },
  methods: {
    addProduct(product) {
      if (
        (this.selectedItems = this.selectedItems.filter(
          (p) => p.id !== product.id
        ))
      ) {
        this.selectedItems.slice(product);
        this.totalPrice -= product.price;
      } else {
        this.selectedItems.push(product);
        this.totalPrice += product.price;
      }
    },
  },
};
</script>

<style>
.total-price {
  width: 324px;
  height: 72px;
}
</style>
tykus's avatar
tykus
Best Answer
Level 104

@boyjarv okay, you're using Vue's options API, so still it should be computed, just different syntax - moving totalPrice from data into computed:

  data() {
    return {
      selectedItems: [],
      itemSelected: false,
    };
  },
  computed: {
    totalPrice() {
      return this.selectedItems.reduce((total, product) => total += product.price, 0)
    } 
  }

Aside, since addProduct should toggle the selection; I would modify the earlier suggestion:

function addProduct(product) {
    var index = selectedItems.findIndex(item => item.id === product.id);

    if (index === -1) {
        selectedItems.push(product);
    } else {
        selectedItems.splice(index, 1);
    }
}
1 like
boyjarv's avatar

Just a quick question around toggling selected class:

I added this to my LI element:

:class="this.selectedItems.includes(item.id) ? ' selected' : ''"
      class="
        w-1/3
        drop-shadow-lg
        bg-white
        rounded-full
        text-black"

it's not working?!

boyjarv's avatar

@tykus

ok I just tried:

:class="this.selectedItems.id.includes(item.id) ? ' selected' : ''"
      class="
        w-1/3
        drop-shadow-lg
        bg-white
        rounded-full
        text-black"

this didn't work either

tykus's avatar

@boyjarv

:class="{selected: selectedItems.some(product => product.id === item.id)}"
1 like
boyjarv's avatar

Thank you, I thought it would be quite simple

Please or to participate in this conversation.