1

I have the following code to filter the table. I select a column from drop-down like age then selects operator from another drop-down like < and search input like 20, And want to search table on them.

Filter :

// 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">

Please read the code comments in JS section to get the idea.

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

JS:

  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 get populated because of first if() but shows empty on second if().

What am i missing ?

Gammer
  • 5,453
  • 20
  • 78
  • 121
  • What are the actual values of `value` and `this.query.search_input` at that point? Could it maybe be that you're trying to compare the two as numbers but they're actually strings? Famous `"2">"10"` returns `true` in Javascript. – sjaustirni Jan 16 '18 at 18:09
  • @sjaustirni the value of `value` is the selected table column values. currently Like i have three row only, When you select a column e.g id, then the values are `22`,`23`,`24`..... And the `this.query.search_input` is the search string i want to search, E.g selected column from dropdown is `age` and the selected condition from dropdown is `>` and the `this.query.search_input` is 20. – Gammer Jan 16 '18 at 18:13
  • Would you make sure that both variables are numbers by parsing the `string`s to `int` and report back whether it helped anything? This may help: https://stackoverflow.com/questions/5630123/javascript-string-integer-comparisons – sjaustirni Jan 16 '18 at 18:15
  • Nope it isn't working for both `string` and `int` – Gammer Jan 16 '18 at 18:16
  • 1
    Hmm. I don't see where it could go wrong there, with my lack of knowledge of context. Would you put up an MCVE example of this behaviour? – sjaustirni Jan 16 '18 at 18:19
  • Updating the question. – Gammer Jan 16 '18 at 18:21
  • @sjaustirni Question uptdated. – Gammer Jan 16 '18 at 18:24

2 Answers2

1

You don't need to iterate over each key of your objects and test if they partially match the desired value. You probably can simplify your filter to something like this

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

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

        // adapt to what your actual operators do
        switch (this.query.search_operator) {
            case 'less_than': return value < this.query.search_input;
            case 'more_than': return value > this.query.search_input;
            // and so on
            default: return false;
        }
    });
}

Note that you probaly will have to use a mechanism to cast your values to numbers if you want to get accurate results. For 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;
            }
        });
    }
}

And a demo

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>
nikoshr
  • 32,926
  • 33
  • 91
  • 105
0

function filter(rows, query) {
  return rows.filter(r => {
    if (query.input.length < 1) {
      return true
    }

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

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

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

I think your filter logic wrong. Maybe you can try this.

Morty Choi
  • 2,466
  • 1
  • 18
  • 26