1

I am trying to target some elements with the Vuejs ref attribute to randomize the order on each page load.

My data is rendered in template and handled in the component:

<div class="team" >
  <div class="team__card" ref="card" v-for="(member, index) in team"
  :key="index">
  <div v-for="(image, imageIndex) in member.image" :key="imageIndex">
    <img :src="image" alt="Photo of team member" :key="imageIndex" />
  </div>
  <div class="team__card-content">
    <p class="font-bold text-xl">{{ member.name }}</p>
    <p class="font-bold text-gray-700">{{ member.title }}</p>
    <p class="text-gray-700">{{ member.description }}</p>
  </div>
 </div>
</div>

<script>
export default {
name: 'Page Name',
data() {
 return {
  team: [
   {
     image: [require('url')],
     name: 'Name',
     title: 'Title',
     description:'description.'
   },
   {
     image: [require('url')],
     name: 'Name',
     title: 'Title',
     description:'description.'
   },
  ]
 }
},
created() {
    this.randomize()
  },
  methods: {
    randomize() {
      for (let i = this.team.length - 1; i > 0; i--) {
        let randomIndex = Math.floor(Math.random() * i)
        let temp = this.team[i]
        this.set(this.team, i, this.team[randomIndex])
        this.set(this.team, randomIndex, temp)
      }
    }
  }
}
</script>

What am i missing here? How do i shuffle/randomize order on each page load of my card element TIA!

jaetp
  • 23
  • 1
  • 5
  • Do you have the `card` refs in a `v-for` (ie there are multiple instances)? If so, I believe `$refs.card` would be an array and as such, would not have an `eq` method – Phil Mar 17 '20 at 02:33
  • Do you have any error messages in your browser console? – Phil Mar 17 '20 at 02:40
  • no error messages! – jaetp Mar 17 '20 at 02:43
  • I believe if you want an array of refs, you **must** use `v-for` – Phil Mar 17 '20 at 02:46
  • ok i will see how i can do that. currently my data structure is handled right in the template. id know how to target these in js or jquery but no idea how DOM manipulation works in vuejs – jaetp Mar 17 '20 at 02:52

2 Answers2

2

The this.set call is missing a $ before set. Without the $, it will cause a runtime error where set is not a function.

this.$set(this.team, i, this.team[randomIndex])
this.$set(this.team, randomIndex, temp)

Alternatively Vue.set could be used; but since set being called within a function where it has access to a Vue instance, $set would be preferred.

Working example:

https://codesandbox.io/s/eager-cori-cu75f

koralarts
  • 2,062
  • 4
  • 30
  • 48
1

You shouldn't be manipulating the DOM manually like that because Vue will just override it during the next update (assuming Vue didn't get confused by those changes).

It doesn't seem like there is any reason why these cards should be hardcoded like that in the template. You should define the data for those cards in an array that you define in the component's data, then render it out using v-for, then all you have to do is shuffle the array.

Here's a demo:

// This is an in-place array shuffle function which is
// compatible with arrays observed by Vue
function shuffleVueArray(array) {
  for (let i = array.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    const temp = array[i];
    Vue.set(array, i, array[j]);
    Vue.set(array, j, temp);
  }
}

new Vue({
  el: '#app',
  data: {
    items: [
      'apple',
      'banana',
      'orange',
      'pear',
      'pineapple',
      'mango',
    ],
  },
  methods: {
    randomize() {
      shuffleVueArray(this.items);
    },
  },
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <button @click="randomize">Randomize</button>
  <ul>
    <li v-for="item of items">{{ item }}</li>
  </ul>
</div>
Decade Moon
  • 32,968
  • 8
  • 81
  • 101
  • I added a demo. Be sure to read up on [change detection caveats](https://vuejs.org/v2/guide/reactivity.html#For-Arrays). – Decade Moon Mar 18 '20 at 02:23
  • Just call `this.randomize()` in the `created` hook. – Decade Moon Mar 18 '20 at 04:28
  • thanks but i've updated my question and the functionality is still not working. ill keep digging – jaetp Mar 18 '20 at 04:53
  • `this.team(target).before` won't work, maybe you thought it was a jQuery object? `this.team` is an array. There should be no DOM manipulation. – Decade Moon Mar 18 '20 at 05:55
  • updated with function not relying on global vue instance since its inside a component. i'm still new to vue and js for that matter, this is why still so hard for me to debug – jaetp Mar 18 '20 at 06:41