Vue: existing array, add click effect and set true?

Viewed 77

I am trying my hands at Nuxt and having a problem that I can't seem to figure out.

The concept:

I am having two arrays, one called items and one called selectedItems. I loop through the array of items to showcase them, if I click them, I simply add them to the array of selectItems and if I click them again, then they are removed from the array. Now I also added a click variable which helps enable coloring in the text to showcase which are selected. I tried simplifying the example with array of [A,B,C] in the code snippet down below!

The problem:

Now in the page, you will already have existing items in the selectedItems like in my example code, whereas [B] already exists in the array. Now how would I on a pageload, set the objects in the array SelectItems, in this case B to have already been clicked? I tried doing a comparing of the items in array Item and array selectedItem via a computed and then a if statement on the component for a class. This worked sorta EXCEPT the element wasn't actually clicked, so you would have to click TWICE in order for the object to be removed in the array. So how do I make the objects from selectedItem be click=true?

Vue.component('Item', {
  template: `
    <div>
      <div :class="{'clicked': clicked,}" @click="selectItem()">
       {{item.name}}
      </div>
    </div>
  `,
  props: {
    item: {
      type: Object,
      default: null,
    },
  },
  data() {
    return {
      clicked: false,
    }
  },
  methods: {
    selectItem() {
      this.clicked = !this.clicked
      const clickedItem = this.item
      const id = clickedItem.id
      if (this.clicked === true) {
        this.$emit('add-item', clickedItem)
      } else {
        this.$emit('remove-item', id)
      }
    },
  },
})

new Vue({
  el: '#demo',
  data() {
    return {
      items: [{id: 1, name: 'a'}, {id: 2,name: 'b'}, {id: 3, name: 'c'}],
      selectedItems: [{id: 2, name: 'b'}],
    }
  },
  methods: {
    addItemToArray(clickedItem){
       this.selectedItems = [...this.selectedItems, clickedItem]
    },
    removeItemFromArray(id){
       this.selectedItems = this.selectedItems.filter(
        (clickedItem) => clickedItem.id !== id
      )
    },
  }
})
.clicked {background-color: coral;}</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
  <template>
    <div v-for="item in items" :key="item.id">
      <Item :item="item" @add-item="addItemToArray"
      @remove-item="removeItemFromArray"> </Item>
    </div>
  </template>
</div>

The code:

https://stackblitz.com/edit/nuxt-starter-cxakbv?file=pages/index.vue

1 Answers

You can try this way:

In index you pass selectedItems to Item component:

<Item :item="item" :selectedItems="selectedItems" @add-item="addItemToArray"
      @remove-item="removeItemFromArray"> </Item>

In Item component add new property selectedItem:

selectedItems: {
  type: Array,
  default: null,
},

And in mounted hook you check is item in selectItems array:

mounted() {
  if (this.selectedItems.some(item => item.id === this.item.id)) this.clicked = true
}

Vue.component('Item', {
  template: `
    <div>
      <div :class="{'clicked': clicked,}" @click="selectItem()">
       {{item.name}}
      </div>
    </div>
  `,
  props: {
    item: {
      type: Object,
      default: null,
    },
    selecteditems: {
      type: Array,
      default: null,
    },
  },
  data() {
    return {
      clicked: false,
    }
  },
  methods: {
    selectItem() {
      this.clicked = !this.clicked
      const clickedItem = this.item
      const id = clickedItem.id
      if (this.clicked === true) {
        this.$emit('add-item', clickedItem)
      } else {
        this.$emit('remove-item', id)
      }
    },
  },
  mounted() {
    if (this.selecteditems.some(item => item.id === this.item.id)) this.clicked = true
  }
})

new Vue({
  el: '#demo',
  data() {
    return {
      items: [{id: 1, name: 'a'}, {id: 2,name: 'b'}, {id: 3, name: 'c'}],
      selectedItems: [{id: 2, name: 'b'}],
    }
  },
  methods: {
    addItemToArray(clickedItem){
       this.selectedItems = [...this.selectedItems, clickedItem]
    },
    removeItemFromArray(id){
       this.selectedItems = this.selectedItems.filter(
        (clickedItem) => clickedItem.id !== id
      )
    },
  }
})
.clicked {background-color: coral;}</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
  <template>
    <div v-for="item in items" :key="item.id">
      <Item :item="item" :selectedItems="selectedItems" @add-item="addItemToArray"
      @remove-item="removeItemFromArray"> </Item>
    </div>
  </template>
</div>

Related