0

Basically what am I doing wrong? This is a chained filter under computed.

Error is 'product.topic.sort' is not a function.

I am trying to use 'select' to have a sort option of ascending, descending, price high & price low.

V-model binds value to the js.

Under filters I'm trying to add a filter that does this sorting based on 'value'

if value = undefined, do nothing.
If value = Az, Ascending
if value = Za, Descending
if value = Ph, Price High
if value = Pl, Price low

Edit

Under filteredSearch() { I have other filters such as

  .filter(product => this.filters.some(filter => product.topic.match(filter))) || 
   this.products
  .filter(p => p.topic.toLowerCase().match(this.search.toLowerCase()))
  .filter(p => p.price <= this.priceFilter)

I want to ensure that all the other filters work with the sort filter.

HTML

<div id="app">
            <h4>Sort</h4>  
                <select v-model="value">
                    <option value="Az">Ascending</option>
                    <option value="Za">Descending</option>
                    <option value="Ph">Price High</option>
                    <option value="Pl">Price Low</option>
                </select>



<div class="block" v-for="product in filteredSearch">
        <h3>{{product.topic}}</h3>
          <p>{{product.price}}</p>
</div>
</div>

JS

var app = new Vue({
            el: '#app',
            data: {
                products: [{
                        "topic": "english",
                        "price": "20"
                    },
                    {
                        "topic": "french",
                        "price": "60"
                    },
                    {
                        "topic": "science",
                        "price": "80"
                    }
                ],
                value: "",
            })



computed: {

filteredSearch() {
return this.products
.filter((product) => {
    if (!this.value)
        return true;
    if (this.value == "Az") {
        return product.topic.sort(function(a, b) {
            a.topic - b.topic
        });
    }
})
}
}
});
5
  • You need to check if (product.topic) Commented Nov 21, 2019 at 14:37
  • How? Sorry I'm new to all of this. Commented Nov 21, 2019 at 14:39
  • What does product look like? Can we see the rest of the code? Can't really tell you what's wrong with just a snippet. Ref: stackoverflow.com/help/how-to-ask Commented Nov 21, 2019 at 14:51
  • provide the demo array which you are trying to filter Commented Nov 21, 2019 at 14:52
  • Have added the updates. Should be a lot clearer now. Commented Nov 21, 2019 at 15:05

2 Answers 2

1

Here's an example of how to do this. So we have a helper method getSorter which looks at the currently selected value which your v-model directive is binding to this.value, and returns an appropriate function to pass to sort based on that. If nothing is selected, it will return null.

In your computed property filteredSearch, you can apply your existing filters as you like, and then sort the outcome of that.

methods: {
    // determine the sorting function to use
    getSorter() { 
      switch (this.value) {
        case 'Za':
          return (a,b) => b.topic > a.topic ? 1 : a.topic == b.topic ? 0 : -1;
        case 'Az':
          return (a,b) => b.topic > a.topic ? -1 : a.topic == b.topic ? 0 : 1;
        case 'Ph':
          return (a,b) => b.price - a.price;
        case 'Pl':
          return (a,b) => a.price - b.price;
        default:
          return null;
      }
    }
  },
  computed: {
    filteredSearch: function() { 
      // apply existing filter logic
      var filteredProducts = this.products
        .filter((el) => true); // replace with your existing filter conditions here

      // apply sort function
      var sortFunction = this.getSorter();
      return sortFunction ? filteredProducts.sort(sortFunction) : filteredProducts;
    }
  }
Sign up to request clarification or add additional context in comments.

2 Comments

Your answer is exactly what I want though, I just don't know how to implement it.
In the code, you already return after filtering - change return this.filters.length && this.products to var filteredProducts = this.filters.length && this.products. And remove the line .filter((el) => true);, that was just an example line for filtering, it does nothing.
1

I think you shouldn't use filter in the computed property function, it's better to just do the sort like this

filteredSearch() {
return !this.value ? 
        true 
        : this.value == "Az" ? 
        this.products.sort((a, b) => a.topic > b.topic ? 1 : -1)
        : this.value == "Za" ?
        this.products.sort((a, b) => a.topic < b.topic ? 1 : -1)
        : this.value == "Pl" ? 
        this.products.sort((a, b) => a.price - b.price)
        : this.value == "Ph" ?
        this.products.sort((a, b) => b.price - a.price)
        : null;
}

2 Comments

I have edited the question slightly. I want all my other filters such as search etc, to work with my sort filter. If I do ^ only sort works and all the others don't.
The function was working with "Pl" and "Ph", I just corrected the first two cases. Please check now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.