Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue.js Filter a multi dimension array in a computed function

I have a Tagging Tool Component with 3 different levels of priority. Now I would like to a filter search. Is it possible to access tags[n] in the computed tagsFilter function?

This my current version: https://jsfiddle.net/hej7L1jy/26/

I would like to replace v-for="tag in tags[n]" with: v-for="tag in tagsFilter" In the moment I receive a TypeError: this.tags.filter is not a function

Does anyone have an idea?

Vue.js Template:

<div id="app">
  <input id="input-search" type="text" class="form-inline pull-right" v-model="textSearch" placeholder='Search...'>
  <div v-for="n in prios">
  <h3>{{n}} tag priority</h3>
    <ul v-if="tagsFilter && tagsFilter.length">
      <li :class="'tagPriority-'+n" v-for="tag in tagsFilter">
        <label class="checkbox-inline"><input name="tags[]" type="checkbox" v-model="tagSelected" :value="tag.id"> {{tag.title}}</label>
      </li>
    </ul>
  </div>
</div>

Vue.js component:

new Vue({
    el: '#app',
        props: {
            selectedTags: {
                type: Array
            }
        },
        data() {
            return {
                prios: [ 1, 2, 3 ],
                tagSelected: [],
                tags: [],
                textSearch: ''
            }
        },
        computed: {
            tagsFilter: function() {
                var textSearch = this.textSearch;
                return this.tags.filter(function(el) {
                    return el.title.toLowerCase().indexOf(textSearch.toLowerCase()) !== -1;
                });
            }
        },
        created: function () {
            this.tagSelected = this.selectedTags;
            this.tags = {"1":[{"id":9,"title":"Auto"}],"2":[{"id":8,"title":"Elektroauto"}],"3":[{"id":10,"title":"BMW i3"},{"id":11,"title":"Opel Ampera"},{"id":12,"title":"Renault TWIZY"}]};       
        }

});
like image 262
hasentopf Avatar asked Oct 25 '25 23:10

hasentopf


1 Answers

Although you define tags in your data:

data() {
    return {
        tags: [],
    }
},

Your created callback overrides this.tags:

created: function () {
    this.tagSelected = this.selectedTags;
    this.tags = {"1":[{"id":9,"title":"Auto"}],"2":[{"id":8,"title":"Elektroauto"}],"3":[{"id":10,"title":"BMW i3"},{"id":11,"title":"Opel Ampera"},{"id":12,"title":"Renault TWIZY"}]};       
}

Turning it into an object, which has no filter method.

Filtering using a computed property

Your template:

<li :class="'tagPriority-'+n" v-for="tag in tags[0]">

Becomes

<li :class="'tagPriority-'+n" v-for="tag in tagsFilter[n]">

And

computed: {
    tagsFilter: function() {
        var textSearch = this.textSearch;
        return this.tags.filter(function(el) {
            return el.title.toLowerCase().indexOf(textSearch.toLowerCase()) !== -1;
        });
    }
},

Becomes:

computed: {
    tagsFilter: function() {
        var textSearch = this.textSearch;
        var filteredTags = {};
        var tags = this.tags;
        Object.keys(this.tags).forEach(function(key) {
            filteredTags[key] = tags[key].filter(function(el) {
                return el.title.toLowerCase().indexOf(textSearch.toLowerCase()) !== -1;
            });
        });
        return filteredTags;
    },
},

Basically, we are iterating each of this.tags properties and adding a filtered version of each of them to filteredTags.

Demo JSFiddle here.



Filtering using a method

Another way (least amount of changed code) is to change your computed into a method with an argument:

<li :class="'tagPriority-'+n" v-for="tag in tags[0]">

Becomes

<li :class="'tagPriority-'+n" v-for="tag in tagsFilter(n)">

And

computed: {
    tagsFilter: function() {
        var textSearch = this.textSearch;
        return this.tags.filter(function(el) {
            return el.title.toLowerCase().indexOf(textSearch.toLowerCase()) !== -1;
        });
    }
},

Becomes:

methods: {
    tagsFilter: function(i) {
        var textSearch = this.textSearch;
        return this.tags[i].filter(function(el) {
            return el.title.toLowerCase().indexOf(textSearch.toLowerCase()) !== -1;
        });
    },
},

Demo JSFiddle here.

like image 169
acdcjunior Avatar answered Oct 28 '25 16:10

acdcjunior