Home > OS >  Filter table based on tags in Javascript
Filter table based on tags in Javascript

Time:07-22

So I am trying to filter my table (element plus table) based on the tags that user clicks. (I am working in a Vue project) table

I have written a method that outputs all the rows that contains the tag clicked by the user.

<el-table-column prop="Keyword" label="Keyword" width="200" ">
      <template #default="scope" >
      <el-tag v-for="(k,index) in (scope.row.Keyword.split(','))" :key="index" @click="handlekey(k)">{{k}} </el-tag>
      </template>    
</el-table-column>

handlekey(val){          
return this.data.filter((item)=>{return item.Keyword.split(',').includes(val)} )     
}

When user clicks on a tag the console output is enter image description here

Now I am trying to filter the table, so when a user clicks on a tag the table only shows the rows which contain that tag. I have tried to write this function is computed but that gives an error sating that $options.handlekey is not a function

I have also tried to change the change the original data by doing this.data = this.data.filter((item)=>{return item.Keyword.split(',').includes(val)} ) at the end of handlekey method but that doesn't work either.

I'll be grateful if anyone could give me suggestions on how I can achieve this.

CodePudding user response:

You need a computed (derived state) which returns all rows containing one of the currently active keywords (if any), or all rows if there are no active keywords.

Instead of feeding the rows into the table, you feed this computed.

What's special about computed is they get recalculated every time the state involved in computing them changes.
Computed never mutate state. Picture a computed as a lens through which you see the state, but you can't actually touch it. If you mutate the source data inside a computed, you will trigger another computing of itself, ending up in an endless loop.

In the example below, the computed renderedRows will recalculate when:

  • rows change
  • the (selected) keywords change

Here's the example:

Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
  el: '#app',
  data: () => ({
    rows: [
      {
        name: '1-5',
        keywords: 'one,two,three,four,five'
      },
      {
        name: '6-10',
        keywords: 'six,seven,eight,nine,ten'
      },
      {
        name: '2n   1',
        keywords: 'one,three,five,seven,nine'
      },
      {
        name: '2n',
        keywords: 'two,four,six,eight,ten'
      },
      {
        name: '3n   1',
        keywords: 'one,four,seven,ten'
      },
      {
        name: '5n   2',
        keywords: 'two,seven'
      }
    ],
    keywords: []
  }),
  computed: {
    renderedRows() {
      return this.keywords.length
        ? this.rows.filter((row) =>
            this.keywords.some((kw) => row.keywords.split(',').includes(kw))
          )
        : this.rows
    },
    allKeywords() {
      return [
        ...new Set(this.rows.map((row) => row.keywords.split(',')).flat())
      ]
    }
  },
  methods: {
    toggleKeyword(k) {
      this.keywords = this.keywords.includes(k)
        ? this.keywords.filter((kw) => kw !== k)
        : [...this.keywords, k]
    }
  }
})
td {
  padding: 3px 7px;
}

button {
  cursor: pointer;
  margin: 0 2px;
}

button.active {
  background-color: #666;
  color: white;
  border-radius: 3px;
}

button.active:hover {
  background-color: #444;
}
<script src="https://unpkg.com/vue@2"></script>
<div id="app">
  <h4>Keywords:</h4>
  <div>
    <button
      v-for="key in allKeywords"
      :key="key"
      v-text="key"
      :
      @click="toggleKeyword(key)"
    />
  </div>
  <h4>Rows:</h4>
  <table>
    <thead>
      <th>Name</th>
      <th>Keywords</th>
    </thead>
    <tbody>
      <tr v-for="row in renderedRows" :key="row.name">
        <td v-text="row.name" />
        <td>
          <button
            v-for="key in row.keywords.split(',')"
            :key="key"
            v-text="key"
            :
            @click="toggleKeyword(key)"
          />
        </td>
      </tr>
    </tbody>
  </table>
</div>

Note: provide what you have in a runnable minimal reproducible example on codesandbox.io or similar and I'll modify it to include the principle outlined above.

  • Related