web-dev-qa-db-fra.com

VueJs - Pagination de table et filtre

J'utilise Vue2.js et Element UI comme cadre. Je voudrais pouvoir filtrer une table qui est tranchée . Pour ce faire, j'utilise les composants table et filter dont la documentation est disponible ici .

Situation OK

La table n'est pas tranchée. Lorsque vous choisissez un filtre, une boucle parcourt chaque ligne et vérifie si la valeur de la colonne est égale au filtre.

Situation NON OK

La table est tranchée. Lorsque vous choisissez un filtre, une boucle parcourt chaque ligne résultant de la tranche et vérifie si la valeur de la colonne est égale à celle du filtre. En faisant cela, nous ne filtrons pas les valeurs "cachées".

J'ai fait un peu https://jsfiddle.net/acm3q6q8/3/ donc c'est plus facile à comprendre. 

Tout cela a du sens puisque je ne travaille pas sur l’ensemble des données, mais sur une version découpée en tranches. 

Une solution pourrait être de masquer les lignes au lieu de les exclure en découpant les données en tranches, mais je me demande s’il existe une meilleure solution?

Ce que je veux réaliser

  • Dans la jsfiddle, n'affichez que 2 éléments. 
  • Filtrez la tag pour n’afficher que les lignes dont la balise est Office

Résultat actuel

Aucune ligne n'est affichée car la ligne dont la variable tag était office ne faisait pas partie de la table en tranches.

Résultat attendu

Lors du filtrage, je souhaite prendre en compte les lignes qui ne sont pas nécessairement affichées. 

Important

Cela devrait fonctionner correctement avec un filtre multiple (c.-à-d. Que je sélectionne plusieurs balises)

MODIFIER

Dans la même mesure, si vous souhaitez trier le nom par ordre alphabétique, Albert ne sera pas affiché si vous n’affichez que 2 éléments.

7
Léo Coco

Vous pouvez gérer l'événement filter-change sur le composant table (documenté ici ) et filtrer/découper vous-même.

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

    },
    computed : {
      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;
      }
    }  
}

Et le modèle

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

Exemple .

2
Bert

Le problème est que le découpage est effectué avant le filtrage. Le filtre doit voir les données d'origine et le comptage de lignes doit faire partie du filtrage.

Étant donné que le filtre examine une ligne à la fois, il est un peu délicat de garder une trace des lignes correspondantes. Ce que j’ai fait ici, c’est de garder un compteur de lignes correspondantes qui est remis à zéro lorsque la ligne examinée est la première ligne de données. C'est hacky, mais ça marche. Il y a peut-être un meilleur moyen; Je ne suis pas familier avec le widget de table.

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.com/element-ui/lib/theme-default/index.css");
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/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>

1
Roy J