0

I am trying to filter and sort an array of objects in Vue. I am able to successfully filter any ranger of filter methods on my list of objects, but when I add a sort function, and conditionally render a specific sort function, the this.sort is undefined in the console. I want to add if statements inside the sort method to dynamically render specfic sorting (ex// alphabetically and time left ...)

<template>
  <div class="cards">
    <CountdownCard
      v-for="(event, index) in filteredItems"
      :key="index"
      :event="event"
    />
  </div>
</template>

<script>
import CountdownCard from '@/components/CountdownCard'
import EventBus from '@/components/EventBus'

export default {
  props: {
    milliseconds: {
      default: 0
    },
    seconds: {
      default: 0
    }
  },
  components: {
    CountdownCard
  },
  data() {
    return {
      events: [
        {
          title: 'Autum',
          date: 'September 22, 2020',
          emoji: '',
          type: 'season',
          year: 2020,
          month: 8,
          day: 22,
          hour: 0,
          minute: 0
        },
        {
          title: 'Christmas',
          date: 'December 25, 2020',
          emoji: '',
          type: 'holiday',
          year: 2020,
          month: 11,
          day: 21,
          hour: 0,
          minute: 0
        },
      ],
      updateSearch: '',
      filter: 'all',
      sort: 'alpha'
    }
  },
  mounted() {
    return (
      EventBus.$on('search-countdowns', search => {
        this.updateSearch = search
      }),
      EventBus.$on('filter-catagories', filter => {
        this.filter = filter
      }),
      EventBus.$on('sort-catagories', sort => {
        this.sort = sort
      })
    )
  },
  computed: {
    filteredItems: function() {
      // filters at work
      return (
        this.events
          // search filter
          .filter(event => {
            return event.title
              .toLowerCase()
              .includes(this.updateSearch.toLowerCase())
          })
          // category filters
          .filter(event => {
            if (this.filter == '' || this.filter == 'all') {
              return this.events
            } else {
              return event.type == this.filter
            }
          })
          // sort alpha
          .sort(function(a, b) {
            if (this.sort == 'alpha') {
              if (a.title < b.title) {
                return -1
              }
              if (a.title > b.title) {
                return 1
              }
              return 0
            }
            // sort dates
            if (this.sort == 'timeLeast') {
              if (a.year < b.year) {
                return 1
              }
              if (a.year > b.year) {
                return -1
              }
              return 0
            }
          })
      )
    }
  }
}
</script>

WHy is the this.sort undefined when right above in the code, this.filter has no errors?

Tyler Morales
  • 1,440
  • 2
  • 19
  • 56
  • You are already using arrow functions, so just use an arrow function for `sort` as well, otherwise `this` will refer to `window` – ibrahim mahrir Aug 07 '20 at 20:11
  • BTW, in the second `filter` the return value should be `return true;` if `this.filter == '' || this.filter == 'all'` – ibrahim mahrir Aug 07 '20 at 20:15
  • Also, why are you using two `filter` calls, you can use just one like so: `this.events.filter(event => event.title.toLowerCase().includes(this.updateSearch.toLowerCase()) && (this.filter == '' || this.filter == 'all' || event.type == this.filter).sort(...)` – ibrahim mahrir Aug 07 '20 at 20:17
  • Also, `this.updateSearch.toLowerCase()` should be cached as you don't have to call `toLowerCase` on `this.updateSearch` for every item in the array. – ibrahim mahrir Aug 07 '20 at 20:20
  • Also, to sort strings correctly use `toLocaleCompare` instead of `<` and `>` which are reserved for numbers – ibrahim mahrir Aug 07 '20 at 20:21
  • Is is possible to have three sort methods chained on, but only have one be in effect. I would like for a user to click from a dropdown the sorting method and then apply that here. If I chain all three .sort's, the entire list will be sorted to all of the conditions @ibrahimmahrir – Tyler Morales Aug 07 '20 at 20:24
  • Chaining `sort`s won't work. Only the last one will be used. BTW, your sorting logic can be a lot shorted if you use `toLocaleCompare` to compare strings and use [this technique](https://stackoverflow.com/q/1063007/) to compare the numbers, like so: https://jsfiddle.net/rsqt9a1c/ – ibrahim mahrir Aug 07 '20 at 20:30
  • @ibrahimmahrir I looked at the jsfiddle and it seems to be working in my local environment. Back to your question about why I had multiple .filter's. I had them there because it was easier to look at. The way you have it seems not as intuitive as clear cut filter methods – Tyler Morales Aug 07 '20 at 20:40
  • Yeah, that's just the usual dilemma we are always facing: **clarity vs performance**. – ibrahim mahrir Aug 07 '20 at 20:44

0 Answers0