最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - VueJs - Table pagination and filter - Stack Overflow

programmeradmin1浏览0评论

I'm using Vue2.js and Element UI as a framework. I would like to be able to filter a table which is sliced. To do so, I use the table and filter ponents whose documentation could be found here.

Situation OK

The table is not sliced. When you picked a filter, a loop goes trough each row and check if the value of the column is equal to the filter.

Situation NOT OK

The table is sliced. When you picked a filter, a loop goes trough each row that results of the slice and check if the value of the column is equal to the filter. By doing that we don't filter the "hidden" values.

I've made a little / so it is easier to understand.

All of this make sense since I'm not working on the whole data, but on a sliced version.

One solution could be to hide rows instead of excluding them by slicing the data, but I'm wondering if there is a better solution ?

What I want to achieve

  • In the jsfiddle, display only 2 items.
  • Filter the tag to display only rows whose tag is Office

Actual result

There is no row displayed since the row whose tag was office was not part of the sliced table.

Expected result

When filtering, I would like to take into account rows that are not necessarily displayed.

Important

This should work fine with a multiple filter (ie I select several tags)

EDIT

In the same extent if you want to sort the name by alphabetical order, Albert won't be displayed if you displayed only 2 items.

I'm using Vue2.js and Element UI as a framework. I would like to be able to filter a table which is sliced. To do so, I use the table and filter ponents whose documentation could be found here.

Situation OK

The table is not sliced. When you picked a filter, a loop goes trough each row and check if the value of the column is equal to the filter.

Situation NOT OK

The table is sliced. When you picked a filter, a loop goes trough each row that results of the slice and check if the value of the column is equal to the filter. By doing that we don't filter the "hidden" values.

I've made a little https://jsfiddle/acm3q6q8/3/ so it is easier to understand.

All of this make sense since I'm not working on the whole data, but on a sliced version.

One solution could be to hide rows instead of excluding them by slicing the data, but I'm wondering if there is a better solution ?

What I want to achieve

  • In the jsfiddle, display only 2 items.
  • Filter the tag to display only rows whose tag is Office

Actual result

There is no row displayed since the row whose tag was office was not part of the sliced table.

Expected result

When filtering, I would like to take into account rows that are not necessarily displayed.

Important

This should work fine with a multiple filter (ie I select several tags)

EDIT

In the same extent if you want to sort the name by alphabetical order, Albert won't be displayed if you displayed only 2 items.

Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked Apr 17, 2017 at 18:15 Léo CocoLéo Coco 4,28211 gold badges59 silver badges100 bronze badges 11
  • The tag filter doesn't appear to work on that fiddle. – Bert Commented Apr 17, 2017 at 18:32
  • Yes it does. If you have all items displayed everything's fine. As soon as you start to slice the table, it filters only on the sliced table and not the whole one. – Léo Coco Commented Apr 17, 2017 at 18:34
  • I mean, when I pick a tag, nothing happens. filterTag is never called. – Bert Commented Apr 17, 2017 at 18:35
  • It does work on my side. I added a console.log in filterTag. Could you check again ? – Léo Coco Commented Apr 17, 2017 at 18:38
  • 1 Tag is fine, you should just Confirm "Office" selection in order to filter rows (click left chineese word under tag selection). – Egor Stambakio Commented Apr 17, 2017 at 18:38
 |  Show 6 more ments

2 Answers 2

Reset to default 2

You can handle the filter-change event on the table ponent (documented here), and filter/slice yourself.

var Main = {
    data() {
      return {
        numberItemToShow : 4,
        tableData: [...],
        filter: []
      }

    },
    puted : {
      filterData() {
          if (!this.filter.length)
            return this.tableData.slice(0, this.numberItemToShow)
          else
            return this.tableData
              .filter(row => this.filter.includes(row.tag))
              .slice(0, this.numberItemToShow);
      }
    },
    methods: {
      onFilterChange(filters){
        if (filters.tag)
            this.filter = filters.tag;
      }
    }  
}

And the template

<template>
<input v-model="numberItemToShow" placeholder="edit me">
<p>Number of item to display: {{ numberItemToShow }}</p>
  <el-table ref="tab" :data="filterData" border style="width: 100%" @filter-change="onFilterChange">
    <el-table-column prop="name" label="Name"   sortable>
    </el-table-column>
    <el-table-column prop="tag" label="Tag" column-key="tag" :filters="[{ text: 'Home', value: 'Home' }, { text: 'Office', value: 'Office' }]">
      <template scope="scope">
        <el-tag :type="scope.row.tag === 'Home' ? 'primary' : 'success'" close-transition>{{scope.row.tag}}</el-tag>
      </template>
    </el-table-column>
  </el-table>
</template>

Example.

The problem is that the slicing is done before the filtering. The filter has to see the original data, and the row-counting must be part of the filtering.

Since the filter looks at one row at a time, keeping track of the matched rows is a little tricky. What I did here is keep a counter of matched rows that resets to zero when the row being looked at is the first row of data. This is hacky, but it works. There may be a better way; I am not familiar with the table widget.

var Main = {
    data() {
      return {
      	numberItemToShow : 4,
        tableData: [{
          name: 'One',
          tag: 'Home'
        }, {
          name: 'Two',
          tag: 'Home'
        }, {
          name: 'Three',
          tag: 'Home'
        }, {
          name: 'Four',
          tag: 'Office'
        }],
        scratchCounter: 0
      }
    },
    methods: {
      filterTag(value, row) {
        const matched = row.tag === value;

        if (row === this.tableData[0]) {
        	this.scratchCounter = 0;
        }
        if (matched) {
        	++this.scratchCounter;
        }
        return this.scratchCounter <= this.numberItemToShow && matched;
      }
    }
  }
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
@import url("//unpkg./element-ui/lib/theme-default/index.css");
<script src="//unpkg./vue/dist/vue.js"></script>
<script src="//unpkg./element-ui/lib/index.js"></script>
<div id="app">
<template>
<input v-model="numberItemToShow" placeholder="edit me">
<p>Number of item to display: {{ numberItemToShow }}</p>
  <el-table :data="tableData" border style="width: 100%">
    <el-table-column prop="name" label="Name">
    </el-table-column>
    <el-table-column prop="tag" label="Tag" :filters="[{ text: 'Home', value: 'Home' }, { text: 'Office', value: 'Office' }]" :filter-method="filterTag">
      <template scope="scope">
        <el-tag :type="scope.row.tag === 'Home' ? 'primary' : 'success'" close-transition>{{scope.row.tag}}</el-tag>
      </template>
    </el-table-column>
  </el-table>
</template>
</div>

发布评论

评论列表(0)

  1. 暂无评论