Menu Close

List Rendering with Vue.js — Object Change Detection and Arrays

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at Vue’s object change detection capabilities and displaying sorted and filtered results.

Object Change Detection

Vue can’t detect property additions or deletions because of the limitations of modern JavaScript.

For example, if we have the following code:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    foo: {  
      a: 1  
    }  
  },  
  methods: {  
    addProperty() {  
      this.foo.b = 2;  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <button @click="addProperty">Add Property</button>  
      <div v-for="value in foo">  
        {{value}}  
      </div>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

Then nothing happens when we click Add Property.

We can fix this by calling Vue.set as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    foo: {  
      a: 1  
    }  
  },  
  methods: {  
    addProperty() {  
      Vue.set(this.foo, "b", 2);  
    }  
  }  
});

and keep index.html the same, we’ll get ‘2’ when we click Add Property.

In the code above, we passed in the object to update as the first argument, the property name as the second argument, and the value of the property as the third argument.

We can also use the this.$set / vm.$set method as follows, where this and vm are a Vue instance.

To use it, we can write the following:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    foo: {  
      a: 1  
    }  
  },  
  methods: {  
    addProperty() {  
      this.$set(this.foo, "b", 2);  
    }  
  }  
});

Then we get the same result as before.

To assign multiple new properties to an existing object, we can use Object.assign or Lodash’s _.extend method by assigning the returned object to the existing variable as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    foo: {  
      a: 1  
    }  
  },  
  methods: {  
    addProperties() {  
      this.foo = Object.assign({}, this.foo, {  
        b: 2,  
        c: 3  
      });  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <button @click="addProperties">Add Properties</button>  
      <div v-for="value in foo">  
        {{value}}  
      </div>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

In the code above, we used the Object.assign method with the empty object as the first argument, the original object as the second argument, and an object with the new properties and values as the third argument.

Then when the page first loads, we have only:

1

listed.

Then when we click Add Properties, we get:

123

This is because clicking Add Properties triggered a call to addProperties , which then calls Object.assign to return a merged object with the new properties, which is then assigned back to this.foo .

That will trigger a view update with the new items.

Displaying Filtered/Sorted Results

We should use computed properties to render filtered or sorted results.

This is a much more efficient way to rendered filtered results than checking each array entry during v-for with v-if since the whole array doesn’t have to rendered and then checked with v-if .

For example, we can render a list of odd numbers from a list of all kinds of numbers as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    numbers: [1, 2, 3, 4, 5]  
  },  
  computed: {  
    oddNumbers() {  
      return this.numbers.filter(n => n % 2 === 1);  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <div v-for="num in oddNumbers">  
        {{num}}  
      </div>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

Then we get:

135

displayed.

We can use methods in situations where computed properties aren’t feasible like inside nestedv-for loops.

For example, we can write a method as follows to render a list of odd numbers:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    numbers: [1, 2, 3, 4, 5]  
  },  
  methods: {  
    oddNumbers(numbers) {  
      return numbers.filter(n => n % 2 === 1);  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <div v-for="num in oddNumbers(numbers)">  
        {{num}}  
      </div>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

In the code above, we called the oddNumbers method with the numbers array passed in to return an array of odd numbers.

Then we can iterate through it by using the v-for loop as usual.

We can display sorted numbers as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    numbers: [1, 2, 3, 4, 5]  
  },  
  computed: {  
    reversedNumbers() {  
      return this.numbers.sort((a, b) => b - a);  
    }  
  }  
});

index.js :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <div v-for="num in reversedNumbers">  
        {{num}}  
      </div>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

We sorted it with the computed property reversedNumbers to sort the numbers in reverse and then the numbers will be displayed in reverse:

54321

Conclusion

Vue can’t detect object property changes and trigger and view update as properties are added or removed.

Therefore, we have to use Vue.set or this.$set to update it. We can pass in the object to update as the first argument, the property name as the second argument, and the value of the property as the third argument.

To add multiple object properties at once, we can use the Object.assign method with the empty object as the first argument, the original object as the second argument, and an object with the new properties and values as the third argument.

To display sorted and filtered array results, we can use computed properties. It’s the most efficient way since only the filtered results are rendered.

If that can’t be done, then we can also use a method to return the filtered or sorted array instead.

Posted in vue