Search Filtering with Vue2

2019-08-20 06:47发布

问题:

    <!-- Facets in the v-for below is an array of objects, each element (facet) in the
    facets array has a property which is an array of facetItems. -->

    <div class="row" v-for="(facet, facetsIndex) in facets" :key="facetsIndex">

      <!-- Since we are inside the v-for, it creates a search input for each facet.
      Each facet search input will only search for facetItems belonging to that facet.
      We know which facet to search in because we pass the facetIndex to the searchFilter function. -->

      <input type="text" @keyup="searchFilter(facetsIndex)">

      <div v-if="facet.facetItems.length > 0">
        <div class="facet-header">{{config[core.toLowerCase()].displayNames[facet.facetName]}}</div>
        <div class="row facet-scroll" >

          <!-- The v-for below is used to iterate over the facetItems for each facet. displayFacetItems() is called
          for each array of facetItems corresponding to each facet on initial render. displayFacetItems() is also called
          on each keyup event emitting from the corresponding facet search input. displayFacetItems() should return an
          array of facetItems objects, and when a search input is entered, it should return a filtererd array of facetItems
          based on the search results. -->

          <div  class="facet-item" v-for="(item, facetItemIndex) in displayFacetItems(facetsIndex)" :key="facetItemIndex">
            <facet v-bind:item="item"  v-bind:facet="facet"></facet>
          </div>

        </div>
        <hr class="divider"/>
      </div>
    </div>

    methods: {
      searchFilter (facetsIndex) {
        let searchTerm = event.currentTarget.value
        this.displayFacetItems(facetsIndex, searchTerm)
      },
      displayFacetItems (facetsIndex, searchTerm) {
        if (!searchTerm) return this.facets[facetsIndex].facetItems
        return this.facets[facetsIndex].facetItems.filter((facetItem) => {
          return _.includes(facetItem.name.toLowerCase(), searchTerm.toLowerCase())
        })
      }
    },

Please see the comments in the code above for an explanation of what's happening in my code.

I don't understand why my code above isn't working. I'm trying to implement search functionality for each facet. When searching, the filtering should only happen for facetItems belonging to that specific facet.

I've been able to verify that displayFacetItems does return an array of filtered facetItems but for some reason the filtered array isn't updated in the DOM.

This might have something to do with Vue's data binding or the process in which Vue updates the DOM. Any pointers on what I'm doing wrong is greatly appreciated.

My code took inspiration from this article:

https://nickescobedo.com/1018/introduction-to-vue-js-filtering-with-lodash

回答1:

The param facetsIndex is not reactive, please take a look at your jsconsole, you should have a warning about this and not only this, your code logic is totally wrong.

  • You could use a v-model on input,
  • create a filteredFacets property,
  • use this property in your loop.

Just an example, you should read more about how VueJS works : https://vuejs.org/v2/guide/



回答2:

You can see my jsfiddle for search items on Vuejs. I hope this will help you.

<div id="app">
    <label>
        Search name: <input type="text" v-model='searchString'>
    </label> <br>
    <transition-group tag='ul' name='my-list'>
        <li v-for='item in filteredList' :key='item.id' class="my-list-item">
            {{item.name}}
        </li>
    </transition-group>
</div>
<script>
   const app = new Vue({
    el: '#app',
    beforeMount() {
        const req = fetch('https://jsonplaceholder.typicode.com/users');
        req.then(response => {
            if (response.ok) {
                return response.json();
            }
            throw new Error('Bad request: ' + response.status);
        })
        .then(users => {
            this.users = users;
            this.nextId = this.users.length + 1;
        });
    },
    data: {
        searchString: '',
        users: [
        {id: 1, name: 'Alex'},
        {id: 2, name: 'Bob'},
        {id: 3, name: 'Sandy'},
        ],
    },
    computed: {
        filteredList: function() {
            const searchString = this.searchString.toLowerCase();
            return this.users.filter(item => item.name.toLowerCase().includes(searchString));
        }
    }
});
</script>