My pany is moving from Angular JS to Vue. It has been very smooth until I needed to replicate the functionailty of an Angular filter into VueJS. The original Angular filter looked like so:
JS
app.filter('unique', function () {
return function (collection, keyname) {
var output = [],
keys = [];
angular.forEach(collection, function (item) {
var key = item[keyname];
if (keys.indexOf(key) === -1) {
keys.push(key);
output.push(item);
}
});
return output;
};
});
In my Vue I have the following:
<select class="u-full-width" v-model="newPost.cat">
<option value="" selected="selected">Choose a Category</option>
<option v-for="post in posts | unique" selected>{{ post.cat }}</option>
</select>
I assume I can still use filters the same, but how do I go about replicating this?
My pany is moving from Angular JS to Vue. It has been very smooth until I needed to replicate the functionailty of an Angular filter into VueJS. The original Angular filter looked like so:
JS
app.filter('unique', function () {
return function (collection, keyname) {
var output = [],
keys = [];
angular.forEach(collection, function (item) {
var key = item[keyname];
if (keys.indexOf(key) === -1) {
keys.push(key);
output.push(item);
}
});
return output;
};
});
In my Vue I have the following:
<select class="u-full-width" v-model="newPost.cat">
<option value="" selected="selected">Choose a Category</option>
<option v-for="post in posts | unique" selected>{{ post.cat }}</option>
</select>
I assume I can still use filters the same, but how do I go about replicating this?
Share Improve this question asked Mar 16, 2017 at 21:45 AuzyAuzy 2,1552 gold badges27 silver badges36 bronze badges 3- What do you mean replicating this? And i thing in Vue2 filters are not supported, and you can use puted methods – Matej Marconak Commented Mar 16, 2017 at 21:49
- Replicate may not be the right word, "mimicking the functionality" may be better. I want to achieve same thing I did in Angular in Vue system. – Auzy Commented Mar 16, 2017 at 21:56
- 1 check answer by Tomasz Rup, this is propadly most conventional way for vuejs2. In vuejs version 1 was filter similar to angularjs 1, but in version 2 was deprecated - you can check this tutorial filters ways in vue2 – Matej Marconak Commented Mar 16, 2017 at 22:06
2 Answers
Reset to default 9You should use a puted property here. Filters in Vue are, as stated by the creator, supposed to be for text transformation mainly (not a rule of course, but I'd still go with a puted property).
On your ponent:
puted: {
uniquePosts: function() {
var output = [];
var keys = [];
this.posts.forEach(function (post) {
var key = post[keyname];
if (keys.indexOf(key) === -1) {
keys.push(key);
output.push(post);
}
});
return output;
}
}
And v-for
the uniquePosts
in your template.
EDIT:
To pass a keyname
:
puted: {
uniquePosts: function () {
var vm = this;
return function (keyname) {
var output = [];
var keys = [];
vm.posts.forEach(function (post) {
var key = post[keyname];
if (keys.indexOf(key) === -1) {
keys.push(key);
output.push(post);
}
});
return output;
};
}
}
And you can call uniquePosts(keyname)
.
EDIT2: Fixed variable names, sorry
To improve on Tomasz' answer, you might define a global mixin in your main.js:
Vue.mixin({
puted: {
unique () {
return function (arr, key) {
var output = []
var usedKeys = {}
for (var i = 0; i < arr.length; i++) {
if (!usedKeys[arr[i][key]]) {
usedKeys[arr[i][key]] = true
output.push(arr[i])
}
}
return output
}
}
}
})
In any of your ponents, pass in the array to filter and the property to filter on in:
<option v-for="post in unique(posts, 'cat')" selected>{{ post.cat }}</option>
Using an object to check which unique keys have been added should be more efficient than indexOf
which has to search the array. Keep in mind you might want to make a Plugin instead of using a global mixin as the Vue docs remend.