ratiw / vuetable-2

data table simplify! -- datatable component for Vue 2.x. See documentation at
https://vuetable.com
MIT License
2.16k stars 399 forks source link

Include bootstrap pagination component by default? #247

Open austenc opened 7 years ago

austenc commented 7 years ago

@ratiw

What do you think about including the bootstrap pagination as a component within vuetable-2 -- the one from this page https://github.com/ratiw/vuetable-2-tutorial/wiki/lesson-19.

That way we don't have to burden the package user with having to create an extra component, because they could use either <vuetable-pagination> or <vuetable-bootstrap-pagination> depending on their use-case. I'd be happy to submit a PR, but wondered if you'd consider this or already had, and decided against it?

ratiw commented 7 years ago

I find that people seem to have different opinion about how it looks and how it should work on their project. That's why I left it out and instead provide some examples on codepen to show how it can be extended to work with Bootstrap3, Bulma, and UIKit.

I personally don't have any objection to add it to the package, but due to the reason mentioned above I afraid that it would add more unneeded files, so I originally thought that if there are enough people using it or have extended it to other CSS framework and I'll will add the links to the README so that they can grab it for use. So far, too busy lately and totally forget about it.

So, I think you could just send PR to include a link to this bootstrap pagination component in the repo's README. So, I don't forget in the next release.

Thanks for asking about this. :)

adavie1 commented 6 years ago

I had a somewhat similar issue- I'm using element-ui since I use vuetable all over the place in my app, I built a component that I can parameterise to behave how I wish.

The code is below, it's a bit hacky around the span calculations, but it will do for version 1.0 of my app.

To meet your usecase of which pagaination to use, I'd suggest having a prop that defaults to your most common use case, and use v-if to manage what to show.

<template>
  <div class="padded">

    <el-row v-if="!hideTop" :gutter="8" style="padding-bottom: 1.3em;">
      <el-col v-if="title" :span="titleSpan">
        <h5 v-if="showTitle">{{title}}</h5>
      </el-col>

      <div>
        <el-col align="middle" :span="searchSpan">
          <filter-bar
          :search-placeholder="searchPlaceholder"
          :show-search="showSearch"
          :show-refresh="showRefresh"
          :setFilterEvent="this.filterEvent"
          :resetFilterEvent="this.filterReset"
          :refreshEvent="this.refreshTable" />
        </el-col>

        <el-col v-if="addAction" :align="(showSearch || showRefresh ? 'middle' : 'right')" :span="addSpan">
          <component v-bind="addProps" :is="addAction"></component>
        </el-col>
      </div>
    </el-row>

    <vuetable :ref="this.tableRef"
    :api-url="getEndpoint(this.url)"
    :fields="this.fields"
    :css="this.tableCss"
    pagination-path=""
    :multi-sort="true"
    multi-sort-key="ctrl"
    :sort-order="sortOrder"
    :detail-row-component="this.detailComponent"
    :append-params="this.moreParams"
    @expiry-item="customAlertHandler"
    @vuetable:cell-clicked="onCellClicked"
    @vuetable:pagination-data="onPaginationData"
    @vuetable:loaded="onLoaded">
  </vuetable>

  <el-row>
    <el-col :span="16">
      <vuetable-pagination-info ref="paginationInfo"></vuetable-pagination-info>
    </el-col>
    <el-col align="right" :span="8">
      <vuetable-pagination ref="pagination"
        @vuetable-pagination:change-page="onChangePage"></vuetable-pagination>
    </el-col>
  </el-row>
</div>
</template>

<script>
import Vue from 'vue'
import VueEvents from 'vue-events'

import DateMixins from '@/mixins/DateMixins'

import Vuetable from 'vuetable-2'
import VuetablePagination from 'vuetable-2/src/components/VuetablePaginationDropdown'
import VuetablePaginationInfo from 'vuetable-2/src/components/VuetablePaginationInfo'

Vue.use(Vuetable)
Vue.use(VueEvents)

Vue.component('vuetable-pagination', Vuetable.VueTablePaginationInfo)
Vue.component('vuetable-pagination-dropdown', Vuetable.VueTablePaginationDropDown)
Vue.component('vuetable-pagination-info', Vuetable.VueTablePaginationInfo)

import FilterBar from '@/components/FilterBar'

export default {
  mixins: [DateMixins],
  components: {
    Vuetable,
    VuetablePagination,
    VuetablePaginationInfo,
    FilterBar
  },
  props: {
    fields: {
      type: Array,
      required: true
    },
    tableRef: {
      type: String,
      default: 'vuetable'
    },
    detailComponent: {
      type: String
    },
    addAction: {
      type: Object
    },
    addProps: {
      type: Object
    },
    title: {
      type: String
    },
    url: {
      type: String
    },
    hideTop: {
      type: Boolean,
      default: false
    },
    showTitle: {
      type: Boolean,
      default: true
    },
    showSearch: {
      type: Boolean,
      default: true
    },
    showRefresh: {
      type: Boolean,
      default: true
    },
    searchPlaceholder: {
      type: String,
      default: 'Search...'
    },
    eventFilter: {
      type: String,
      default: 'filter-set'
    },
    eventFilterReset: {
      type: String,
      default: 'filter-reset'
    },
    eventRefresh: {
      type: String,
      default: 'refresh-table'
    },
    sortField: {
      type: String,
      default: 'name'
    },
    sortDirection: {
      type: String,
      default: 'asc'
    },
    params: {
      type: Object,
      default: () => {}
    }
  },

  data () {
    return {
      defaultTitleSpan: 8,
      defaultSearchSpan: 12,
      defaultAddSpan: 4,
      filterEvent: this.eventFilter,
      filterReset: this.eventFilterReset,
      refreshTable: this.eventRefresh,
      paramsDone: false,
      hasParams: false,
      moreParams: this.params,
      sortOrder: [
        {
          field: this.sortField,
          sortField: this.sortField,
          direction: this.sortDirection
        }
      ],
      tableCss: {
        tableClass: 'el-table',
        ascendingIcon: 'glyphicon glyphicon-chevron-up',
        descendingIcon: 'glyphicon glyphicon-chevron-down',
        sortHandleIcon: 'glyphicon glyhicon-menu-hamburger'
      }
    }
  },

  computed: {
    titleSpan: function () {
      var search = (this.showSearch && this.refresh ? 0 : (this.showRefresh && !this.showSearch ? this.defaultSearchSpan - 6 : this.defaultSearchSpan))
      var add = (this.noAdd ? this.defaultAddSpan : 0)
      return this.showTitle ? this.defaultTitleSpan + search + add : 0
    },
    searchSpan: function () {
      return this.showSearch ? this.defaultSearchSpan : (this.showRefresh ? (this.noAdd ? 8 : this.showTitle ? 4 : 18) : 0)
    },
    addSpan: function () {
      return this.noAdd ? 0 : this.showSearch ? this.defaultAddSpan : this.defaultAddSpan + 2
    }
  },

  methods: {
    getTableRef () {
      return this.tableRef
    },

    getRefreshEvent () {
      return this.refreshTable
    },

    refresh () {
      this.$refs[this.tableRef].refresh()
    },

    customAlertHandler (data) {
      alert('Custom Alert for ' + data)
    },

    onPaginationData (paginationData) {
      this.$refs.pagination.setPaginationData(paginationData)
      this.$refs.paginationInfo.setPaginationData(paginationData)
    },

    onChangePage (page) {
      this.$refs[this.tableRef].changePage(page)
    },

    onCellClicked (data, field, event) {
      this.$refs[this.tableRef].toggleDetailRow(data.id)
    },

    onFilterSet (filterText) {
      this.moreParams = {
        'filter': filterText
      }

      Vue.nextTick(() => this.$refs[this.tableRef].refresh())
    },

    onFilterReset () {
      this.moreParams = {}
      this.$refs[this.tableRef].refresh()
      Vue.nextTick(() => this.$refs[this.tableRef].refresh())
    },

    onLoaded () {
      if (!this.paramsDone) {
        var params = this.$root.$data.routes.currentRoute.params.id

        if (params) {
          this.onFilterSet(params)
        }

        this.paramsDone = true
      }
    }
  },
  created () {
    this.sortOrder.field = (this.sortField ? this.sortField : 'name')
    this.sortOrder.sortField = (this.sortField ? this.sortField : this.sortOrder.field)
    this.sortOrder.direction = (this.sortDirection ? this.sortDirection : this.sortOrder.direction)

    this.filterEvent = this.tableRef + '-' + this.filterEvent
    this.filterReset = this.tableRef + '-' + this.filterReset
    this.refreshTable = this.tableRef + '-' + this.refreshTable
  },

  mounted () {
//    console.log('Data Table', this.tableRef, 'SPANs: title', this.titleSpan, 'search', this.searchSpan, 'add', this.addSpan, 'TOTAL', (this.titleSpan + this.searchSpan + this.addSpan))
    this.$events.listen(this.filterEvent, filterText => this.onFilterSet(filterText))
    this.$events.listen(this.filterReset, this.onFilterSet)
    this.$events.listen(this.refreshTable, this.refresh)

    this.refresh()
  },
  beforeDestroy () {
    this.$events.remove(this.filterEvent)
    this.$events.remove(this.filterReset)
    this.$events.remove(this.refreshTable)
  }
}
</script>
cristijora commented 6 years ago

For me, the current solution is find because it allows changing your desired pagination. Here is an example with element-ui where I basically set the pagination component to be something else than the one provided in vuetable http://jsfiddle.net/z11fe07p/2702/