I was wondering about using filters in vue
I know computed and when i use it but my question is
i used this code to sort fruits array instead of using computed
<li v-for="fruit in fruits.sort() ">{{fruit }}</li>
it run and i got the result correctly
but console notified me for error
[Vue warn]: You may have an infinite update loop in a component render function.
(found in <MyFilter> at C:\xampp\htdocs\projects\max\___explaning\169_filters_mixins\src\MyFilter.vue)
warn @ VM6599:564
flushSchedulerQueue @ VM6599:2340
(anonymous) @ VM6599:511
nextTickHandler @ VM6599:460
when i removed .sort() the warn disappeared
the question : why this warn appeared and is there any way to add .sort() to v-for array without using computed values
Going off number 2, because VueJS filters are meant for text transformations, they can only be used in two places: mustache interpolations (the curly braces in your template) and in v-bind expressions.
A Filter is a simple JavaScript function which is used to change the output of a data to the browser. Filters in Vue. JS don't change the data directly wherever we store them, it only applies formatting to our data. The data remains the same only the output of a data to a browser is changed.
v-for directive is a Vue. js directive used to loop over a data usually an array or object. First, we will create a div element with id as app and let's apply the v-for directive to an element with data. Now we will create this data by initializing a Vue instance with the data attribute containing the value.
Vue has a convenient shorthand for v-on : the @ symbol. For example, @click is functionally equivalent to v-on:click .
You're getting the error because you are creating an infinite loop when calling fruit.sort()
in the v-for
statement.
fruit.sort()
causes the array of be mutated (updated) and when Vue gets notified of this update, it attempts to update the DOM and then evaluate the v-for
statement. This again will call fruit.sort()
and then trigger an update.
Naive answer:
Instead you could use v-for="fruit in fruits.map(f => f).sort()"
, although this may become quite heavy if the list is somewhat large. What this does is two things: 1) fruits.map(f => f)
creates a new array containing the same values as fruits
, and then 2) it sorts the newly created one.
Better answer:
Rather than inlining the copying and sorting inside the template (where it shouldn't be, you could use a method which does the same. You want to put as much logic as possible outside of the templates.
{
...Other component properties...
methods: {
sorted(arr) {
// Return a copy of the sorted array
return arr.map(e => e).sort()
}
}
...Other component properties...
}
Also better answer:
If you'd been using Vue 1.x, you could have used filters for this (v-for="fruit in fruits | orderBy"
, but using filters outside of text interpolation ({{ }}
) has been removed from Vue 2.x and instead Vue's official migration guide suggests using computed properties for this exact thing.
Now, I'd still suggest not mutating the array inside the computed properties, but instead copy the array first and then sorting it, or perhaps even follow their guide and use lodash's orderBy(...)
function for this.
{
...Other component properties...
computed: {
sortedFruits() {
// Return a copy of the sorted array
return this.fruits.map(f => f).sort()
}
}
...Other component properties...
}
Hope this helps.
Edit: Here's a pen displaying this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With