Filtering an Array of Objects on the Fly in Vue.js

I'm currently working on a Vue.js app where I need to dynamically apply filter values to an Array of objects based on their field values. Each object in the Array has various fields that I want to filter by. The challenge is that each field can have multiple values for filtering.

So far, I haven't been successful in implementing this filtering functionality. I've attempted to use JavaScript's built-in filter function, but unfortunately, it always gives me an empty result set. To provide some context, I've created a Fiddle showcasing my code:

new Vue({
  el: '#app',
  data: {
    currentFilterProperty: '',
    currentFilterValue: '',

    cols: [
      { title: 'Name', prop:'name' },
      { title: 'Age', prop:'age' },
      { title: 'Birthday', prop:'birthday' },      
    ],

    dataFilters: [],
    data: [
      { name:'Patricia Miller', age:69, birthday:'04-15-1948' },
      { name:'Bill Baggett', age:62, birthday:'05-07-1955' },      
      { name:'Maxine Thies', age:21, birthday:'11-28-1995' },      
      { name:'Alison Battle', age:65, birthday:'08-07-1952' },      
      { name:'Dick Triplett', age:25, birthday:'08-27-1982' } 
    ]
  },

  methods: {
    addFilter: function() {
      var f = this.dataFilters[this.currentFilterProperty];
      if (!f) {
        this.dataFilters = {};
        this.dataFilters[this.currentFilterProperty] = [ this.currentFilterValue ];
      } else {
        this.dataFilters[this.currentFilterProperty].push(this.currentFilterValue);
      }

      // How do I actually apply these filters?
    }
  }
})

I'm struggling with how to properly implement the filters on the data object.

Answer №1

Here is a detailed solution: To begin testing, apply the filter for Age 62, followed by Birthday 04-15-1948, then search 'tri' in Name Patricia.

new Vue({
  el: '#app',
  data: {
    filteredProperty: 'name',
    query: '',
    activeFilters: [],
    data: [
      {name: 'Patricia Miller', age: 62, birthday: '04-15-1948'},
      {name: 'Bill Baggett', age:62, birthday: '04-15-1948' },
      {name:'Maxine Thies', age:62, birthday:'11-28-1948'},
      {name:'Alison Battle', age:65, birthday:'08-07-1952'},      
      {name:'Dick Triplett', age:25, birthday:'08-27-1982'}
    ]
  },
  computed: {
    filtered () {
      var filtered = this.data
      this.activeFilters.forEach(filter => {
        filtered = filtered.filter(record => {
          return filter.name === 'name'
            ? new RegExp(filter.value, 'i').test(record[filter.name])
            : record[filter.name] == filter.value
        })
      })
      return filtered
    }
  },
  methods: {
    addFilter () {
      this.activeFilters.push({
        name: this.filteredProperty,
        value: this.query
      })
      this.query = ''
    },
    removeFilter (idx) {
      this.activeFilters.splice(idx, 1)
    }
  }
})
<div id="app">
  <div>
    <select v-model="filteredProperty">
      <option value="name">Name</option>
      <option value="age">Age</option>
      <option value="birthday">Birthdate</option>
    </select>
    <input placeholder="filter value" v-model="query">    
    <button @click="addFilter">add filter</button>
  </div>
  <hr>
  <table v-if="activeFilters.length">
    <tr style="width: 100px">
      <th colspan="3">Filters in use:</th>
    </tr>
    <tr v-for="(filter, index) in activeFilters" :key="index">
      <td>{{ _.capitalize(filter.name) }}:</td>
      <td>{{ filter.value }}</td>
      <td style="padding-left: 10px;">
        <a href="#" @click.prevented=removeFilter(index)>
          remove
        </a>
      </td>
    </tr>
  </table>
  <hr v-if="activeFilters.length">
  <table>
    <tbody>
      <tr v-for="(record, index) in filtered" :key="index">
        <td style="padding-right:18px;">{{ record.name }}</td>
        <td style="padding-right:18px;">{{ record.age }}</td>
        <td>{{ record.birthday }}</td>
      </tr>
    </tbody>
  </table>  
</div>

<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/lodash"></script>

Answer №2

Review the code snippet below. Modify your approach by turning your method into a computed property so that the filter process occurs automatically without needing to click a button. The provided fiddle currently filters based on Name, so you will need to make adjustments to accommodate all filter criteria, but this should set you on the right path.

new Vue({
  el: '#app',
  data: {
    currentFilterProperty: '',
    currentFilterValue: '',  
    cols: [
      { title: 'Name', prop:'name' },
      { title: 'Age', prop:'age' },
      { title: 'Birthday', prop:'birthday' }  
    ],
    data: [
      { name:'Patricia Miller', age:69, birthday:'04-15-1948' },
      { name:'Bill Baggett', age:62, birthday:'05-07-1955' },      
      { name:'Maxine Thies', age:21, birthday:'11-28-1995' },      
      { name:'Alison Battle', age:65, birthday:'08-07-1952' },      
      { name:'Dick Triplett', age:25, birthday:'08-27-1982' } 
    ]
  },
  computed:{
  filteredData(){
    var self = this;
        // Add condition for currentFilterProperty == 'Name'
    if(this.currentFilterValue != undefined && this.currentFilterValue != ''){
      return this.data.filter(function(d){
        //alert(d.name + " " + this.currentFilterValue);
      return d.name.indexOf(self.currentFilterValue) != -1;
      });          
      }
      // else if(currentFilterProperty == 'Date'){
      // return this.data.filter(function(d){
        
      //return d.birthday.indexOf(self.currentFilterValue) != -1;
      //});
      else{
      return this.data;
      }    
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.4/vue.min.js"></script>

<div id="app">
  <div>
    <select v-model="currentFilterProperty">
      <option v-for="c in cols" :value="c.prop">{{c.title}}</option>
    </select>
    
    <input placeholder="filter value" v-model="currentFilterValue" />
  </div>
  <hr />

  <table>
    <tbody>
      <tr v-for="(record, index) in filteredData">
        <td style="padding-right:18px;">{{ record.name }}</td>
        <td style="padding-right:18px;">{{ record.age }}</td>
        <td>{{ record.birthday }}</td>
      </tr>
    </tbody>
  </table>  
</div>

Answer №3

Here is a successful solution achieved by checking the condition of "captaining."

new Vue({
  el: '#app',
  data: {
    currentFilterProperty: 'name',
    currentFilterValue: '',
    filteredData:[],
    cols: [
      { title: 'Name', prop:'name' },
      { title: 'Age', prop:'age' },
      { title: 'Birthday', prop:'birthday' },      
    ],

    dataFilters: [],
    addFilters:[],
    data: [
      { name:'Patricia Miller', age:69, birthday:'04-15-1948' },
      { name:'Bill Baggett', age:62, birthday:'05-07-1955' },      
      { name:'Maxine Thies', age:21, birthday:'11-28-1995' },      
      { name:'Alison Battle', age:65, birthday:'08-07-1952' },      
      { name:'Dick Triplett', age:25, birthday:'08-27-1982' } 
    ]
  },
  
  methods: {
    addFilter: function() {
     if(!this.currentFilterValue){
      return false;
     }
      var obj = {};
      this.addFilters.push({name:this.currentFilterProperty,value:this.currentFilterValue});
      this.currentFilterValue = "";
    var vm = this;
      this.dataFilters = this.data
      //var temp = [];
      for(var i in vm.addFilters){
        this.dataFilters = this.dataFilters.filter(function(a,b){
        return ((a[vm.addFilters[i].name]).toString().toLowerCase()).indexOf((vm.addFilters[i].value).toString().toLowerCase()) !== -1;
        });
      }
      // How can we implement the filter?
    }
  },
  mounted(){
    this.dataFilters = this.data;
  }
})
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <div>
    <select v-model="currentFilterProperty">
      <option value="name">Name</option>
      <option value="age">Age</option>
      <option value="birthday">Birthdate</option>
    </select>
    <input placeholder="filter value" v-model="currentFilterValue" />
    
    <button v-on:click="addFilter">
    Add Filter
    </button>
  </div>
  <div v-for="(filter,index) in addFilters">{{filter.name}} : {{filter.value}}</div>
  <hr />

  <table>
    <tbody>
      <tr v-for="(record, index) in dataFilters">
        <td style="padding-right:18px;">{{ record.name }}</td>
        <td style="padding-right:18px;">{{ record.age }}</td>
        <td>{{ record.birthday }}</td>
      </tr>
    </tbody>
  </table>  
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

troubleshooting problems with AJAX calls and routing in Angular

I am a beginner with Angular and I recently completed a tutorial on Single Page Application development using templates imported from PHP files, along with Resource and Route modules. Below is the JavaScript code from my project: (function(){ var app ...

An error has occurred with the Firefox Addon: the module `path` cannot be located within the resource://gre/modules/commonjs/http.js

Currently developing a Firefox add-on on Windows10 with node v5.8.0 and npm v3.5.3, using Firefox v.45.0 The issue arises from the following line of code: var path = require("path"); The error message reads: Message: Module `http` is not found at resou ...

unable to add browse-sync to Ubuntu 16.04

I recently installed nodejs and npm and attempted to install browser-sync using the command npm install -g browser-sync. However, I encountered an error. npm install -g browser-sync npm ERR! Linux 4.15.0-101-generic npm ERR! argv "/usr/bin/nodejs" "/ ...

What is the proper method to set up jQuery in scripts loaded via AJAX? I keep receiving the error message: 'Uncaught TypeError: Object #<Object> has no method'

I have developed a website with an index page that contains a div for loading the content of each individual page. Initially, I included external JS files and performed initializations within each separate page. However, most of the time when the page loa ...

Revising the $.parseJSON Function in jQuery 1.9.1 to Match jQuery 1.8.3's Implementation

With the latest version of jQuery, 1.9.0, there have been changes in the implementation of $.parseJSON which is causing some issues for us. We relied on how earlier versions of jQuery handled null and empty strings, where it would return a null value inste ...

What is the process for getting non-event javascript instructions to function properly once a DOM element has been added

After inserting DOM elements (such as an AJAX response), event-delegation is necessary to ensure that events work properly. But what about basic JavaScript instructions? All instructions are organized by affected PHP page to simplify code updates and avoi ...

Why can't JQuery/javascript's dynamic gallery's images be used as buttons instead of links?

I've been struggling with my online portfolio for several nights as I build my website. Despite exhaustive internet searches, I couldn't quite articulate my problem in words and tried multiple workarounds. To see the issue, please visit the beta ...

Enabling or disabling a button dynamically in Ionic based on a conditional statement

I am looking to dynamically enable or disable buttons based on specific conditions. The data is retrieved from Firebase, and depending on the data, I will either enable or disable the button. For example, if a user passes the First Quiz, I want to enable ...

What should you choose between vuex "store" and "data: store" in the Vue() constructor?

Vue documentation recommends using the "data" option in the constructor to maintain global or shared data: Link This approach seems logical and practical. Contrastingly, Vuex documentation initializes the "store" object without specifying a property name ...

Master the art of adjusting chart width on angular-chart with the help of chart.js

I am currently using angular-chart along with Angular and chart.js to create multiple charts on a single page. However, I am facing an issue where each chart is taking up the entire width of the screen. I have tried various methods to limit the width based ...

.ajax() triggers a page refresh upon pressing the ENTER key

Utilizing Ajax to update the database with a new folder leads to page refresh when hitting ENTER. On the form, I have onkeypress="if(event.keyCode==13) savefolder();". Below is the Javascript code where pressing enter calls savefolder function that sen ...

Why is my Vue view not being found by Typescript (or possibly Webpack)?

npx webpack TS2307: Cannot locate module './App.vue' or its corresponding type declarations. I am currently utilizing webpack, vue, and typescript. My webpack configuration is pretty basic. It uses a typescript file as the entry point and gener ...

Ten instances of $digest() being triggered upon the implementation of custom filters

I am struggling with the following angular markup: <tr ng-repeat="dia in dias"> <td>{{ dia[0].fecha }}</td> <td ng-repeat="bloque in bloques"> <div ng-repeat="hora in dia|soloBloque:bloque|sacarHoras"> ...

Restrictions on the number of characters based on the size of fonts in an html list sc

Recently, I attempted to implement a ticker message on my website using li scroller. However, it appears that there is a limitation on the number of characters that can be displayed in the ticker message when different font sizes are used. With a smaller ...

What is the best way to eliminate the background color from one span after selecting a different one?

I created a span element that changes its background color when clicked, but I want the background color to switch to the newly clicked span while removing it from the previously clicked one. Can someone help me achieve this? CSS list-sty ...

Tips for managing cookies in an Angular.js project

At the moment, I am utilizing an AngularJS application. To store certain values in a cookie, I incorporated the angular-cookies-min script to add values to cookies. The following code snippet was used to save values to a cookie: $cookieStore.put("userIn ...

When attempting to insert the "$binary" key into MongoDB using Node.js, an error occurs stating that the key must not begin with a "$" symbol

When utilizing the node driver to insert records into mongo, I encountered an issue with a certain field in my collection: { "$binary": "base64 encoded binary" }. If I directly input a key beginning with $, it triggers an error: Error: key $binary must no ...

What is the best way to ensure that the closing </a> tag remains on the same line while all other tags are placed on a new line in a Vue

vue/html-closing-bracket-newline is causing an unexpected space after the link text, leading to conflicts and errors in prettier and eslint. I am searching for a straightforward configuration change to resolve this issue without resorting to individual lin ...

Deselect an item from a three.js scene by clicking on it

In my three.js scene, I have multiple OBJ models, some already loaded in the scene and others added via a button click. If a user adds an object but later decides to remove it, I am seeking guidance on how to accomplish this effectively. My ideal solutio ...

When the child content surpasses the height of the parent, you can scroll within an overflow:visible; div

My sidebar navigation menu includes children and sub-children that are revealed on hover. You can view a simplified version of it in this jsfiddle link: https://jsfiddle.net/s096zfpd/ Although the example provided is basic, my main concern arises when the ...