58

How can I sort an array by name or sex before displaying it in a v-for loop? https://jsfiddle.net/rg50h7hx/

<div id="string">
  <ul>
    <li v-for="array in arrays">{{ array.name }}</li>
  </ul>
</div>
// Vue.js v. 2.1.8
var string = new Vue({
  el: '#string',
  data: {
    arrays: [
      { name: 'kano',    sex: 'man' },
      { name: 'striker', sex: 'man' },
      { name: 'sonya',   sex: 'woman' },
      { name: 'sindell', sex: 'woman' },
      { name: 'subzero', sex: 'man' }
    ]
  }
})

Do I have to use a "computed", or whatever?

Eliran Malka
  • 15,821
  • 6
  • 77
  • 100
user3798618
  • 758
  • 1
  • 7
  • 12
  • You might try making a getter method which sorts the array before returning. Edit: looks like that might be exactly what you're referring to by computed. See the documentation here: https://vuex.vuejs.org/en/getters.html – Christopher Mar 19 '17 at 07:07
  • 1
    @Christopher Thank you. I wanted to study pure vue, maybe vuex for me is too difficult... – user3798618 Mar 19 '17 at 07:30
  • I think you would need to make sure to presort the data when it is set then. You could technically even do something like data: { arrays: [3, 2, 1].sort() }. Note you'll need to use the sort function with a callback to sort by an object property. – Christopher Mar 19 '17 at 07:38
  • Try using filter before reverse: https://stackoverflow.com/a/67557323/3569935 – Alchie May 16 '21 at 13:41

5 Answers5

82

Yes, an easy way to do this can be create a computed property which can return the sortedArray, like following:

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);
  }
}

See working demo.

You can find the documentation of sort here which takes a compareFunction.

compareFunction Specifies a function that defines the sort order. If omitted, the array is sorted according to each character's Unicode code point value, according to the string conversion of each element.

Saurabh
  • 71,488
  • 40
  • 181
  • 244
  • Can I ask you another question? Why are two functions used here? How does the second function know what exactly needs to be passed to A and what to B? – user3798618 Mar 19 '17 at 12:24
  • @user3798618 Please see added details, Let me know if any issue? – Saurabh Mar 19 '17 at 12:43
  • 1
    I had to add .toUpperCase() to a.name and b.name to make sure that it would not order capital letters first and lowercase second. – MomasVII Jun 05 '18 at 00:55
  • 15
    here, the computed property has a side effect, this.arrays is sorted on place so this.arrays and this.sortedArray share the same reference. You should clone the array and sort it if you want to use a computed property. If you want to sort this.arrays directly, use a watcher. – frlinw Aug 18 '19 at 01:53
  • 1
    there have an error with unexpected side effects. . . .to avoid it please copy the main arrays. . . vue will complaint. . . ex: this.arrays.slice().sort(compare); – Mowazzem Hosen Jul 10 '20 at 04:39
  • @frlinw - yes. This statement in the docs is misleading: "Sometimes we want to display a filtered or sorted version of an array without actually mutating or resetting the original data. In this case, you can create a computed property that returns the filtered or sorted array." From https://vuejs.org/v2/guide/list.html#Displaying-Filtered-Sorted-Results – MSC Sep 15 '20 at 04:52
35

with arrow functions es6:

sortedArray(){
    return this.arrays.sort((a, b) => a.name - b.name );
}
Taha Azzabi
  • 2,392
  • 22
  • 31
  • Is there a similar concise way to sort this in the reverse order? – Catfish Apr 16 '18 at 23:19
  • yes ,just reverse with Less than operator <, for instance `this.arrays.sort((a, b) => a.name < b.name )` – Taha Azzabi Apr 16 '18 at 23:35
  • 3
    Note that `>` returns only 0 (equal) or 1 (greater) while sort compare function must return negative, zero or positive, otherwise sorting will be invalid. Instead of `>` use `-` for numbers: `(a, b) => a - b`, or write a valid compare function with `if` or anything. (see sort on MDN: https://mzl.la/2QcCQ8V) – iman Sep 08 '18 at 07:05
  • 2
    `a - b` does not work for strings, as it returns `NaN`. The answer is wrong. – defnull Mar 10 '20 at 08:30
18

Html side

<div id="string">
      <ul>
        <li v-for="array in sortArrays(arrays)">{{ array.name }}</li>
      </ul>
    </div>

Vue js code || Using Lodash

var string = new Vue({
  el: '#string',
  data: {
    arrays: [
      { name: 'kano',    sex: 'man' },
      { name: 'striker', sex: 'man' },
      { name: 'sonya',   sex: 'woman' },
      { name: 'sindell', sex: 'woman' },
      { name: 'subzero', sex: 'man' }
    ]
  },
  methods: {
     sortArrays(arrays) {
            return _.orderBy(arrays, 'name', 'asc');
        }
  }
})
  • in orderBy function, first argument is array, 2nd argument is key (name / sex) 3rd argument is order (asc / desc)
arora
  • 869
  • 7
  • 12
Rayees Pk
  • 2,503
  • 1
  • 23
  • 19
  • 2
    your function is being called from a for loop and so for every item in the array, will your function be evaluated thereby hindering performance? – Nitin Jain Mar 21 '20 at 14:25
8

This works really cool:

sortFunc: function (){
  return this.arrays.slice().sort(function(a, b){
    return (a.name > b.name) ? 1 : -1;
  });
}

call the function from HTML:

<div id="string">
 <ul>
   <li v-for="array in sortFunc()">{{ array.name }}</li>
 </ul>
</div>
Samir Rahimy
  • 2,580
  • 1
  • 18
  • 10
  • hi, thanks this worked well for me and I managed to get my table rows in descending order by using return (a.ID < b.ID) ? 1 : -1; the issue I have now is when I add a new row, it adds in the bottom table row rather than the top. here is the code I use to add the new row. this.breakData.unshift({ Name: "[New Break]", Active: this.filterAdd, Description: "", BreakTime: 5, IncludeInActiveTime: false, }); – Steven Collins Apr 22 '21 at 08:08
  • its ok, I fixed this issue by using push instead of unshift. hope this helps someone else. – Steven Collins Apr 22 '21 at 08:24
0

Easy way; You can use computedArray instead of array

computed: {
computedFonksiyon() {
  this.arrays.sort(function(x, y) {
    return y.name- x.name;
  });
  return this.arrays;
}
}
Mahir Altınkaya
  • 407
  • 6
  • 15