Search code examples
vue.jscomputed-properties

Using Computed Properties inside Methods in vueJs


I'm trying to create a shuffle function in vue.js. So, for this i created a computed properties and then i call a method. but it doesn't working. I've created two more function 'add' and 'remove' these two working fine except 'shuffle'.

Throwing an error: Uncaught TypeError: this.moveIndex is not a function

var app = new Vue({
  el: '#root',
  data: {
    tasks: [1,8,9],
    nextNum: 10
  },
  computed: {
    moveIndex: function(array){
      var currentIndex = array.length, randomIndex, tempVal;
      for(var i = currentIndex - 1; i > 0; i--){
        randomIndex = Math.floor(Math.random() * currentIndex);
        tempVal = array[i];
        array[i] = array[randomIndex];
        array[randomIndex] = tempVal;
      }
      return array;
    }
  },
  methods: {
    randIndex: function(){
      return Math.floor(Math.random() * this.tasks.length);
    },
    add: function(){
      this.tasks.splice(this.randIndex(),0,this.nextNum++)
    },
    remove: function(){
      this.tasks.splice(this.randIndex(),1)
    },
    shuffle: function(){
      var arr = this.tasks;
      arr = this.moveIndex(arr)
    }
  }
});
.bar-enter-active, .bar-leave-active{
  transition: all 1s;
}
.bar-enter, .bar-leave-to{
  opacity: 0;
  transform: translateY(30px)
}
.bar-move{
  transition: transform 1s 
}
.numbers{
  margin-right: 10px;
  display: inline-block
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>

	<div id="root">
		<button @click="add">Add</button>
		<button @click="remove">Remove</button>
		<button @click="shuffle">Shuffle</button>
		<transition-group name="bar" tag="div">
			<span v-for="task in tasks" :key="task" class="numbers">{{task}}</span>
		</transition-group>
	</div>


Solution

  • Computed properties are just getter functions that return a value and are dependent on other reactive properties.

    1. Your computed property moveIndex is just modifying an array data property i.e this.tasks. So just use a method instead.

    2. You are trying to directly modify an item of the this.tasks array using index. Vue cannot detect such array modifications.

    So use this.$set() or Array.prototype.splice() instead.

    Here are the changes:

    var app = new Vue({
      el: "#root",
      data: {
        tasks: [1, 8, 9],
        nextNum: 10
      },
      methods: {
        randIndex: function() {
          return Math.floor(Math.random() * this.tasks.length);
        },
        add: function() {
          this.tasks.splice(this.randIndex(), 0, this.nextNum++);
        },
        remove: function() {
          this.tasks.splice(this.randIndex(), 1);
        },
        shuffle: function() {
          var array = this.tasks;
          var currentIndex = this.tasks.length;
          var randomIndex;
          var tempVal;
    
          for (var i = currentIndex - 1; i > 0; i--) {
            randomIndex = Math.floor(Math.random() * currentIndex);
            tempVal = array[i];
            this.$set(array, i, array[randomIndex]);
            this.$set(array, randomIndex, tempVal);
          }
        }
        
      }
    });
    

    Here is a working fiddle