Filter a Vue table by column name with specific conditions

I am working on code that filters a table based on user input. The process involves selecting a column from a drop-down menu, choosing an operator from another drop-down menu, and entering a search value. I want to filter the table based on these criteria.

Here is the filtering setup:

// Select column name
<select class="dv-header-select" v-model="query.search_column">
    <option v-for="column in columns" :value="column">{{column}}</option>
</select>

// Select condition(<,>,<=,>=) 
<select class="dv-header-select" v-model="query.search_operator">
    <option v-for="(value, key) in operators" :value="key">{{value}}</option>
</select>

// Search value
<input type="text" class="dv-header-input" placeholder="Search"
    v-model="query.search_input">

To understand the logic behind this code, please refer to the comments provided.

  <tr v-for="row in getSearchedRow">
      <td v-for="(value, key) in row">{{value}}</td>
  </tr>

For the JavaScript section:

  data() {
    return {
    model: { data: [] },
    // populating on API call
    columns: {},
    query: {
        search_column: 'id',
        search_operator: 'equal',
        search_input: ''
    }
  },

  getSearchedRow: function() {

    return this.model.data.filter(row => {
      let value = row[this.query.search_column];
      for(var key in row){
        if(String(row[key]).indexOf(this.query.search_input) !== -1){

          // Return true required to populate table
          if(this.query.search_column.length < 1) {
            return true;
          }

          // when condition gets here, The table shows 0 records
          if(this.query.search_operator == 'less_than') {
            return value < this.query.search_input;
          }

        }
      }
    });
  }

The table gets populated initially but appears empty when the second if() statement is reached.

What could be causing this issue?

Answer №1

Instead of iterating over each key in your objects and testing for partial matches with the desired value, consider simplifying your filter using the following approach:

getSearchedRow: function() {
    if (this.query.search_column === '')
        return this.model.data;

    return this.model.data.filter(row => {
        const value = row[this.query.search_column];

        // Adjust based on your specific operators
        switch (this.query.search_operator) {
            case 'less_than': return value < this.query.search_input;
            case 'more_than': return value > this.query.search_input;
            // Add more cases as needed
            default: return false;
        }
    });
}

It's important to note that you may need to implement a mechanism to convert your values to numbers for accurate results. Here's an example:

data() {
    return {
        model: { data: [
            {id: 1, x: "a", age: 18},
            {id: 2, x: "a", age: 19},
            {id: 3, x: "b", age: 22},
            {id: 4, x: "b", age: 20},
        ] },
        columns: {
          id: {
              cast: function(v) {
                  return +v;
              }
          },
          age: {
              cast: function(v) {
                  return +v;
              }
          }
        },
        query: {
            search_column: 'age',
            search_operator: 'equal',
            search_input: ""
        }
    };
},

computed: {
    getSearchedRow: function() {
        if (this.query.search_column === '')
          return this.model.data;

        const col = this.query.search_column;
        const requiredval = (this.columns[col] && this.columns[col].cast) ? this.columns[col].cast(this.query.search_input) : this.query.search_input;

        return this.model.data.filter(row => {
            const value = row[col];

            switch (this.query.search_operator) {
                case 'less_than': return value < requiredval;
                case 'more_than': return value > requiredval;
                case 'equal': return value === requiredval;

                default: return false;
            }
        });
    }
}

Check out the demo below:

new Vue({
    el: '#app',
    data() {
        return {
            model: { data: [
                {id: 1, x: "a", age: 18},
                {id: 2, x: "a", age: 19},
                {id: 3, x: "b", age: 22},
                {id: 4, x: "b", age: 20},
            ] },
            columns: {
              id: {
                  cast: function(v) {
                      return +v;
                  }
              },
              age: {
                  cast: function(v) {
                      return +v;
                  }
              }
            },
            query: {
                search_column: 'age',
                search_operator: 'equal',
                search_input: ""
            }
        };
    },

    computed: {
        getSearchedRow: function() {
            if (this.query.search_column === '')
              return this.model.data;
        
            const col = this.query.search_column;
            const requiredval = (this.columns[col] && this.columns[col].cast) ? this.columns[col].cast(this.query.search_input) : this.query.search_input;
            
            return this.model.data.filter(row => {
                const value = row[col];
                
                switch (this.query.search_operator) {
                    case 'less_than': return value < requiredval;
                    case 'more_than': return value > requiredval;
                    case 'equal': return value === requiredval;
                    
                    default: return false;
                }
            });
        }
    }
});
<script src="https://unpkg.com/vue"></script>


<div id="app">
  <select class="dv-header-select" v-model="query.search_column">
      <option value="">Everything</option>
      <option value="id">ID</option>
      <option value="age">Age</option>
      <option value="x">X</option>
  </select>


  <select class="dv-header-select" v-model="query.search_operator">
      <option value="equal">=</option>
      <option value="less_than">&lt;</option>
      <option value="more_than">&gt;</option>
  </select>

<input type="text" class="dv-header-input" placeholder="Search"
    v-model="query.search_input">

  <table>
    <tr v-for="row in getSearchedRow">
        <td v-for="(value, key) in row">{{value}}</td>
    </tr>
  </table>
</div>

Answer №2

function validateInput(data, query) {
  return data.filter(d => {
    if (query.input.length < 1) {
      return true
    }

    if (query.col.length < 1) {
      return true
    }

    const value = d[query.col]
    const input = query.input
    switch (query.op) {
      case '=':
        return value == input
      case '<':
        return value < input
      case '>':
        return value > input
      case '<=':
        return value <= input
      case '>=':
        return value >= input
      default:
        throw "unreachable"
    }
  })
}

const dataset = [{
  id: 1,
  age: 20
}, {
  id: 2,
  age: 30
}]
console.log(validateInput(dataset, {
  col: 'id',
  op: '=',
  input: '2'
}))
console.log(validateInput(dataset, {
  col: 'age',
  op: '<',
  input: '25'
}))
console.log(validateInput(dataset, {
  col: '',
  op: '<',
  input: '25'
}))
console.log(validateInput(dataset, {
  col: 'id',
  op: '<',
  input: ''
}))

I believe there is an issue with your current filtering logic. You may want to consider using this alternative implementation.

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

Utilize VueJS to filter out specific options from a select dropdown menu

In my interface, there are 3 drop-down menus that interact with each other based on the selected subject. When a subject is chosen in the first menu, it should affect the options displayed in the other 2 menus. For instance, if "Economics" is selected in ...

Utilizing jQuery Deferred or Promise to synchronize the completion of multiple asynchronous $.post requests

I'm attempting to make three separate jQuery posts, storing their results in variables that are accessible outside of their scope. Once all three posts have returned successfully, I want to execute another function. Currently, I am using nested callba ...

Implementing the 'bootstrap tour' feature in a Ruby on Rails application

I have integrated bootstrap-tour.min.css and bootstrap-tour.min.js into my project. <script type="text/javascript" src='bootstrap-tour.min.js'></script> <link rel="stylesheet" type="text/css" href="bootstrap-tour.min.css"> Her ...

The function mysql_query() in PHP is unable to execute the requested SQL query

Here is the SQL query I have been working with: UPDATE approved_student SET barcode='11', phone='11', table_name='2', remark='' WHERE studentid='5230010'; UPDATE approved_student SET barcode='22&apos ...

Adding a background image in javascript using data from a MySQL database

My current tech stack includes CodeIgniter, vanilla JavaScript, AJAX, CSS, and MySQL. I am trying to figure out how to set the background of an image that is stored in a MySQL database. While the following code is error-free and working perfectly, my cha ...

Navigating the issue of "Experiencing additional hooks rendered compared to the previous render"

I'm currently in the process of developing a small application where certain elements will be nested within one another. My approach involves segmenting each component into its own file (children), returning a function with two components in each Rend ...

Extracting data from JSON array

The output I am receiving is: [{"ref":"contact.html","score":0.7071067811865475}] $.getJSON( "index.json", function(data) { idx = lunr.Index.load(data); var searchResults = idx.search(variabletosearch); var formattedResults = JS ...

Can you please provide information on the callback function type used in the filter method of TypeScript?

transactionsData = [ { id: 101, name: 'transaction 1' }, { id: 201, name: 'transaction 2' }, { id: 301, name: 'transaction 3' }, { id: 401, name: 'transaction 4' } ]; constructor( private objGreetingsSe ...

Troubleshooting why the Angular innerHTML function is failing to render the specified

I'm encountering this problem where I am receiving a string const str = '<p>Please ensure Process Model diagram represents Functions adequately (boxes that represent an activity or group of activities that produce an outcome):</p>< ...

Developing a component instead of a clicked event

My goal with Angular is to create a functionality similar to Google Maps. I have a background image/map, and I want to replace the map with an object/component where the user clicks with the mouse. Currently, I am able to obtain the x/y values. However, I ...

Looking to divide a multiple-page .TIFF document into several PNG or JPG files using the sharp module in node.js?

Is there a way to split a single .tiff file with multiple pages into several .png or .jpg files without using ImageMagick or GraphicsMagick due to limitations in my codebase? I am unable to install CLI tools so I'm exploring alternate solutions. I kn ...

Node.js equivalent of hash_hmac

I am facing an issue while trying to sign the URL in a Node.js application similar to how it is done in my PHP app. In PHP, I use the following code to sign the URL: private static function __getHash($string) { return hash_hmac('sha1', $stri ...

JavaScript code for modifying style properties

Is there a way to modify this function so that when the heading is changed successfully, a "Change Back!" button appears? And then, with a click on the button, the heading is reset and the button disappears again. function changer () { var textArea = ...

Inform the parent Vue container of the starting value

I have set up a Vue container with radio button inputs: <template lang='pug'> each v in [ 1, 500, 1000 ] input( v-model='value', value=v ) label( for=v ) </template> <script lang='ts'> ...

Collaborate using JavaScript SDK V2 to share folders on Dropbox

I am currently working on integrating a service into my Angular 2 application that interacts with the Dropbox service using Javascript SDK V2. Here is how my model is structured: User creates a folder containing photos -> user shares the folder within ...

How much space should be left from the edge for jQuery UI dialog to be

Typically, a dialog is centered using the following code: $(el).dialog('option', 'position', 'center'); Is there a method to specify a "minimum" distance from the side? For example, ensuring that the top position is always a ...

Encountered a problem while attempting to remove node version

When I run the command nvm ls -> v4.3.2 system default -> 4.3.2 (-> v4.3.2) node -> stable (-> v4.3.2) (default) stable -> 4.3 (-> v4.3.2) (default) iojs -> N/A (default) Upon running nodejs --version, it returns v0 ...

Passing information from the created hook to the mounted hook in VueJS

How can I transfer data from the created function to the mounted function in VueJS? In my VueJS application, the code in my created function is as follows: created: function(){ $.getJSON({ url: 'static/timeline.json', success:function( ...

Which option offers superior performance: using attributes through HTML or jQuery?

At times, I find myself needing to include special classes, divs, and attributes in my HTML code for jQuery scripts to function properly (the site's "no-JavaScript" version doesn't require these elements). You probably understand what I mean. I& ...

How can I invoke a custom function asynchronously with JavaScript?

Incorporating a specific angular third party module into my application has posed some challenges. This module offers various call-back methods such as login success and failure, where I have embedded my custom scripts for execution. However, the current ...