Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
vuetables-2
<template>
<div id="users">
<div class="row">
<vuetable-filter-bar
class="col-sm-6"
/>
<!-- Api call should return standard Laravel paginate() json -->
<vuetable-pagination
ref="pagination"
class="col-sm-6"
@vuetable-pagination:change-page="onChangePage"
/>
</div>
<!-- Generate the table based on the default api call -->
<vuetable
ref="vuetable"
:fields="fields"
:css="css"
:sort-order="sortOrder"
:append-params="moreParams"
:http-fetch="getUsers"
class="table-striped table-hover"
api-url="/admin/users"
pagination-path=""
@vuetable:pagination-data="onPaginationData"
>
<template
slot="roles"
slot-scope="props"
>
<!-- Iterate the roles and build the buttons -->
<button
v-for="role in props.rowData.roles"
:key="role.name"
class="btn btn-sm btn-primary mr-1 mb-1"
>
{{ role.name }}<!--&nbsp;<i class="fas fa-times"/>-->
</button>
<!-- add role button fires the modal -->
<button
class="btn btn-sm btn-default text-dark mr-1 mb-1"
@click="addRoles(props.rowData)"
>
<i class="fas fa-pencil-alt"/>
</button>
</template>
</vuetable>
<div class="row">
<!-- Api call should return standard Laravel paginate() json -->
<vuetable-pagination-dropdown
ref="paginationDropdown"
class="offset-sm-6 col-sm-6"
@vuetable-pagination:change-page="onChangePage"
/>
</div>
<!-- Modal for the updating the current users roles -->
<div
id="rolesModal"
class="modal fade"
tabindex="-1"
role="dialog"
>
<div
class="modal-dialog modal-dialog-centered"
role="document"
>
<div class="modal-content">
<form
name="rolesForm"
action=""
method="put"
@submit.prevent="saveRoles"
>
<input
type="hidden"
name="_method"
value="put"
>
<input
:value="user.username"
name="user"
type="hidden"
>
<div class="modal-header">
<h5 class="modal-title">Roles for User "{{ user.name }}"</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div
v-for="role in roles"
:key="role.name"
class="col-sm-4"
>
<!--
Checkboxes are bound to a non-indexed array where the id
is the value of the array item
-->
<div class="form-group">
<label :for="role.name">
<input
:id="role.name"
:value="role.name"
v-model="newRoles"
type="checkbox"
>
{{ role.name }}
</label>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-default"
data-dismiss="modal"
>
Close&nbsp;<i class="fas fa-times"/>
</button>
<button
type="button"
class="btn btn-danger"
@click="newRoles = []"
>
None&nbsp;<i class="fas fa-trash-alt"/>
</button>
<button
type="submit"
class="btn btn-primary"
>
Save&nbsp;<i class="fas fa-save"/>
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
import Vuetable from 'vuetable-2'
// Bootstrap 4 style pagination
import VuetablePagination from '../Vuetable/VuetablePaginationBootstrap'
import VuetablePaginationDropdown from '../Vuetable//VuetablePaginationDropdownBootstrap'
import VuetableCss from '../Vuetable/VuetableCss'
import fieldsDef from './usersFieldsDef'
import VuetableFilterBar from '../Vuetable/VuetableFilterBarBootstrap'
export default {
components: {
Vuetable, // The vuetable
VuetablePagination, // nav/button based pagination
VuetablePaginationDropdown, // select based pagination
VuetableFilterBar // Search
},
data () {
return {
css: VuetableCss, // Reusable Css
fields: fieldsDef, // Field Definitions / rendering
sortOrder: [{
field: 'name',
direction: 'asc'
}],
data: [], // Table data
user: {}, // Current user
roles: {}, // All of the available roles
newRoles: [], // List of roles to be synced when submitted
moreParams: {} // Sends the filter with the other params
}
},
mounted () {
// Listen for the filter events from VuetableFilterBar
this.$events.$on('filter-set', eventData => this.onFilterSet(eventData))
this.$events.$on('filter-reset', e => this.onFilterReset()) // eslint-disable-line no-unused-vars
this.getRoles() // Get all the available roles
},
methods: {
/* Search Filter Handling */
onFilterSet (filterText) {
// console.log('filter-set', filterText)
this.moreParams = {
filter: filterText
}
// console.log(this.$refs.vuetable)
Vue.nextTick( () => this.$refs.vuetable.refresh() ) // eslint-disable-line no-undef
},
onFilterReset () {
// console.log('filter-reset')
this.moreParams = {}
Vue.nextTick( () => this.$refs.vuetable.refresh() ) // eslint-disable-line
},
// Show the modal with the roles of the current user
addRoles(user) {
this.user = user
// Create the non-indexed array "newRoles"
this.newRoles = this.user.roles.map((role) => {
return role.name
})
$('#rolesModal').modal('show') // eslint-disable-line no-undef
},
// Fetch all of the avilable roles that can be used
getRoles: function() {
this.axios.get('/admin/roles') // eslint-disable-line no-undef
.then(({ data }) => {
this.roles = data.data
})
},
// replaces the vuetales own call to api-url to handle jwt auth
getUsers(apiUrl, httpOptions) {
return this.$http.get(apiUrl, httpOptions)
},
// Save the response from the modal form using Laravel resource controller
saveRoles: function() {
axios.put('/admin/users/'+this.user.id, { // eslint-disable-line no-undef
params: {
query: {
user: this.user,
roles: this.newRoles
}
}
}).then(() => {
// Reload the table and hide the modal
this.$refs.vuetable.reload() // Reload keeps the current page number
$('#rolesModal').modal('hide') // eslint-disable-line no-undef
}) // Do we need a catch?
},
// Trigger the pagination changes
onPaginationData (paginationData) {
this.$refs.pagination.setPaginationData(paginationData)
this.$refs.paginationDropdown.setPaginationData(paginationData)
},
onChangePage (page) {
this.$refs.vuetable.changePage(page)
}
}
}
</script>
<style>
/* .vuetable-th-checkbox-id {
width: 2%;
}
.vuetable-th-id {
width: 8%;
} */
.vuetable-th-username {
width: 20%;
}
.vuetable-th-name {
width: 20%;
}
.vuetable-th-email {
width: 15%;
}
.vuetable-th-slot-roles {
width: 65%;
}
.vuetable-pagination nav {
float: right;
}
.vuetable-pagination-dropdown nav {
float: right;
}
</style>
// Deals with the sort icons using fontawesome
export default {
tableClass: 'table',
loadingClass: 'loading',
ascendingIcon: 'fas fa-arrow-down',
descendingIcon: 'fas fa-arrow-up',
detailRowClass: 'vuetable-detail-row',
handleIcon: 'fas fa-bars',
sortableIcon: '', //fas fa-sort-amount-up', // since v1.7
ascendingClass: 'sorted-asc', // since v1.7
descendingClass: 'sorted-desc' // since v1.7
}
<template>
<div class="vuetable-filter-bar">
<div class="form-inline">
<div class="form-group">
<label class="sr-only">Search for:&nbsp;</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-btn">
<button
class="btn btn-primary"
type="button"
@click="doFilter"
>
<i class="fas fa-search"/>
</button>
</span>
</div>
<input
v-model="filterText"
class="form-control"
placeholder="Search string"
type="text"
@keyup.enter="doFilter"
>
<div class="input-group-append">
<span class="input-group-btn">
<button
class="btn btn-default"
type="button"
@click="resetFilter"
>
<i class="fas fa-times"/>
</button>
</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
filterText: ''
}
},
methods: {
doFilter () {
this.$events.fire('filter-set', this.filterText)
},
resetFilter () {
this.filterText = ''
this.$events.fire('filter-reset')
}
}
}
</script>
<template>
<div class="vuetable-pagination">
<nav aria-label="Table Navigation">
<ul class="pagination">
<li
:class="{'disabled': isOnFirstPage}"
class="page-item">
<a
class="page-link"
href="#"
@click.prevent="loadPage(1)">
<span><i class="fas fa-angle-double-left"/></span>
</a>
</li>
<li
:class="{'disabled': isOnFirstPage}"
class="page-item">
<a
class="page-link"
href="#"
@click.prevent="loadPage('prev')">
<span><i class="fas fa-angle-left"/></span>
</a>
</li>
<template v-if="notEnoughPages">
<li
v-for="n in totalPage"
:key="n"
:class="{'active': isCurrentPage(n)}"
class="page-item"
>
<a
class="page-link"
@click.prevent="loadPage(n)"
v-html="n"/>
</li>
</template>
<template v-else>
<li
v-for="n in windowSize"
:key="n"
:class="{'active': isCurrentPage(windowStart+n-1)}"
class="page-item"
>
<a
class="page-link"
@click.prevent="loadPage(windowStart+n-1)"
v-html="windowStart+n-1"/>
</li>
</template>
<li
:class="{'disabled': isOnLastPage}"
class="page-item"
>
<a
class="page-link"
href=""
@click.prevent="loadPage('next')">
<span><i class="fas fa-angle-right"/></span>
</a>
</li>
<li
:class="{'disabled': isOnLastPage}"
class="page-item"
>
<a
class="page-link"
href=""
@click.prevent="loadPage(totalPage)">
<span><i class="fas fa-angle-double-right"/></span>
</a>
</li>
</ul>
</nav>
</div>
</template>
<script>
import { VuetablePaginationMixin } from 'vuetable-2'
export default {
mixins: [VuetablePaginationMixin]
}
</script>
<template>
<div class="vuetable-pagination-dropdown">
<nav aria-label="Table Navigation">
<ul class="pagination">
<li
:class="{'disabled': isOnFirstPage}"
class="page-item">
<a
class="page-link"
href="#"
@click.prevent="loadPage(1)">
<span><i class="fas fa-angle-double-left"/></span>
</a>
</li>
<li
:class="{'disabled': isOnFirstPage}"
class="page-item">
<a
class="page-link"
href="#"
@click.prevent="loadPage('prev')">
<span><i class="fas fa-angle-left"/></span>
</a>
</li>
<div class="form-group mr-1 ml-1">
<select
id="paginationDropdown"
class="form-control"
@change="loadPage($event.target.selectedIndex+1)"
>
<template
v-for="k in totalPage"
>
<option
:key="k"
:value="k"
:selected="isCurrentPage(k)"
>
Page {{ k }}
</option>
</template>
</select>
</div>
<li
:class="{'disabled': isOnLastPage}"
class="page-item"
>
<a
class="page-link"
href=""
@click.prevent="loadPage('next')">
<span><i class="fas fa-angle-right"/></span>
</a>
</li>
<li
:class="{'disabled': isOnLastPage}"
class="page-item"
>
<a
class="page-link"
href=""
@click.prevent="loadPage(totalPage)">
<span><i class="fas fa-angle-double-right"/></span>
</a>
</li>
</ul>
</nav>
</div>
</template>
<script>
import { VuetablePaginationMixin } from 'vuetable-2'
export default {
mixins: [VuetablePaginationMixin]
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment