0
votes

I'm using Vue cli and I have an array of users that I display as a profile card in template that I would like to sort by name. I'm using Vuex to store data.

In the child component I have in my template:

<div class="outside"  v-for="(item, index) in arrays" :key="item.id" v-bind:id="item.name">
    <div class="stay">  <p class="n"> {{ item.name }}</p> </div>

and I'm getting the Vuex data:

computed: {
    arrays () {
      return this.$store.state.arrays
    },
}

and my array contains:

 arrays: [
      { name: 'Peter'},
      { name: 'Beth'},
      { name: 'Daniel'},
    ]

I used a function in the child component:

computed:{
   sortedArray: function() {
    function compare(a, b) {
      if (a.name < b.name)
        return -1;
      if (a.name > b.name)
        return 1;
      return 0;
    }

    return this.arrays.sort(compare);
  }
  },

and changed the template to:

<div class="outside"  v-for="(item, index) in sortedArrays" :key="item.id" v-bind:id="item.name">

But I'd like a way to do this onclick (in the parent), instead of always displaying it in order.

In my parent component I have:

<div class="begin">
<div class="b">Sort By:
                
 <select name="sort" class="sort" >
  <option value="name" @click="sortArrays()">Name</option>
 </select>
 </div>

<childComponent></childComponent>

</div>

I would like a sortArrays function I can use in the parent to display the user profile card in alphabetical order when I click on sort by name.

Thanks so much!

3

3 Answers

2
votes

You can send the array from parent to child in props

Using Props

Parent

.html

<div class="begin">
  <div class="b">Sort By:
            
     <select name="sort" class="sort" >
        <option value="name" @click="sortArray()">Name</option>
     </select>
  </div>

  <childComponent :arrays=arrays></childComponent>

</div>

.Vue

new Vue({
  data() {
    return {
      arrays: this.$store.state.arrays
    }
  },
  methods: {
    sortArray: function() {
       this.array.sort((a, b) => return a.name < b.name ? -1 : 1)
    }
  }
})

Child

.Vue

new Vue({
   props: ['arrays']
})

Using Sort flag

Child component will accept a sort prop from parent. When Sort is clicked on parent it will be true and sent to child. On Prop Change, the child will sort and display the sorted array.

Child

.Vue

new Vue({
  props: ['isSorted],
  watch: {
    isSorted: function(oldval, newVal){
      if(newVal) {
        // Do the sorting
      }
    }
  }
})

Parent

.Vue

 new Vue({ data(){ return { isSorted: false }}, methods: { sortArrays: { this.isSorted = true; } }})

.html

  <child-component :isSorted=isSorted></child-component>

Update

The change event can be binded to select.

<select name="sort" class="sort" @change="sortArray" v-model="filter">
    <option value="name">Name</option>
 </select>

In Vue

props: { filter: ''},
methods: { sortArray: function() { if(this.filter === 'name') // Do the sorting }}
1
votes

Add a showSorted in your data with a bool value:

data(){
   return {
    showSorted: false
   }
 }

then edit your computed to use showSorted:

computed:{
   sortedArray: function() {
    function compare(a, b) {
      if (a.name < b.name)
        return -1;
      if (a.name > b.name)
        return 1;
      return 0;
    }
    if(this.showSorted){
        return this.arrays.sort(compare);
     }
     return this.arrays;
  }
  },

and then onClick you just have to set this.showSorted to true;

1
votes

Move the array, sortedArray computer properties to the parent component And pass the array you want to be displayed to the child component as prop

handle all the logic in the parent component, here is a code snippet below that shows the basic operation. Hope you can make changes as you need.

var ChildComponent = {
  template: "<div>{{ sortedArray }}</div>",
  props: {
    sortedArray: {
      type: Array,
      default: () => [],
    }
  }
}

var app = new Vue({
  el: '#app',
  components: { ChildComponent },
  data: {
     sortBy: "",
     array: [
      { name: 'Peter', age: 24},
      { name: 'Beth', age: 15},
      { name: 'Daniel', age: 30},
    ]
  },
  computed: {
    displayArray() {
      // declare the compare functions
      // for name
      function cmpName(a, b) {
        if (a.name < b.name)
          return -1;
        if (a.name > b.name)
          return 1;
        return 0;
      }
      // for age
      function cmpAge(a, b) {
        if (a.age < b.age)
          return -1;
        if (a.age > b.age)
          return 1;
        return 0;
      }
      
      if (this.sortBy === "name") return this.array.sort(cmpName);
      else if (this.sortBy === "age") return this.array.sort(cmpAge);
      else return this.array;
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <select v-model="sortBy">
    <option value="">Please select a value</option>
    <option value="name">name</option>
    <option value="age">age</option>
  </select>
  <child-component :sorted-array="displayArray" />
</div>