-
Notifications
You must be signed in to change notification settings - Fork 23
Pagination Filtering Sorting Searching Together
Samayun Chowdhury edited this page Nov 28, 2020
·
4 revisions
composer create-project --prefer-dist laravel/laravel ECommerce "8"
composer require laravel/ui --dev
php artisan ui vue --auth
npm install admin-lte vue-router vuex @fortawesome/fontawesome-free moment vform view-design
npm install
npm run watch
[...]
<template>
<Page
:total="filterString.total"
:current="filterString.page"
:page-size="filterString.perPage"
@on-change="changePaginatedPage"
@on-page-size-change="changePaginatedPerPage"
show-total
show-elevator
show-sizer
prev-text="Previous"
next-text="NeXT"/>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
export default {
computed: {
...mapGetters("categoriesStoreIndex",['filterString']),
},
methods:{
...mapActions("categoriesStoreIndex" , ['changePaginatedPage','changePaginatedPerPage'])
}
}
</script>
export default {
state: {
filterString:{
page: 1,
perPage : 6,
orderBy: 'created_at',
sortBy: 'desc',
q: "",
total: 0
}
},
getters: {
filterString : state => state.filterString,
getFilteredURLString : state => {
let {page,perPage,orderBy,sortBy,q} = state.filterString;
let queryString = "";
if (q != "") {
queryString = `page=1&q=${q}`
} else {
queryString = `page=${page}`
}
(perPage !="") ? queryString += `&perPage=${perPage}` : null;
(orderBy !="") ? queryString += `&orderBy=${orderBy}` : null;
(sortBy !="") ? queryString += `&sortBy=${sortBy}` : null;
return queryString;
}
},
actions : {
async getCategories({commit ,state , getters}){
try {
commit('SET_IS_LOADING' , true)
let res = await axios.get(`/api/admin/categories?${getters.getFilteredURLString}`);
if (res.status == 200) {
let updatedFilterString = {
page: parseInt(res.data.current_page),
perPage :parseInt(res.data.per_page),
total: parseInt(res.data.total)
}
commit('FILTER_DATA', updatedFilterString)
commit('FETCH_CATEGORIES' , res.data.data);
commit('SET_IS_LOADING' , false)
}
} catch (error) {
commit('SET_IS_LOADING' , false)
if (error.response.status == 403) {
$Notice.error({
title: 'Category FETCH Failed!',
desc: error.response.data.message
});
}
}
},
changePaginatedPage({state,commit ,dispatch } , page){
commit('FILTER_DATA', {page})
dispatch('getCategories')
},
changePaginatedPerPage({state,commit , dispatch} , perPage){
commit('FILTER_DATA', {perPage})
dispatch('getCategories')
}
},
mutations: {
FETCH_CATEGORIES(state , categories){
state.categories = categories
},
FILTER_DATA(state , payload){
// state.filterString = payload
// update only @given credentials
for(let obj in payload){
state.filterString[obj] = payload[obj]
}
},
}
}
[](https://github.com/samayun/ecommerce-laravel-vue/blob/master/docs/images/pagination.png
// web.php
[...]
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Admin\CategoryController;
Route::group(['prefix' => 'api/admin' , 'middleware' => 'auth:admin' ], function () {
Route::resource('categories' , CategoryController::class);
});
[...]
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
use HasFactory;
protected $guarded = [];
public function scopeSearch($query , $q)
{
if($q == null) return;
return $query->where('name','LIKE', "%$q%");
}
}
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Policies\CategoryPolicies;
use App\Models\Category;
use Illuminate\Http\Request;
class CategoryController extends Controller
{
public function __construct()
{
$this->authorizeResource(Category::class, 'category');
}
public function index(Request $request){
$perPage = $request->has('perPage') ? $request->query('perPage') : 5;
$orderBy = $request->has('orderBy') ? $request->query('orderBy') : 'created_at';
$sortBy = $request->has('sortBy') ? $request->query('sortBy') : 'desc';
$q = $request->has('q') ? $request->query('q') : '' ;
// these code must be efactored - we wil need this again and again
return Category::search($q)->orderBy($orderBy , $sortBy)->paginate($perPage );
}
}
<template>
<Page
:total="meta.total"
:current="meta.page"
:page-size="meta.perPage"
@on-change="changePaginatedPage"
@on-page-size-change="changePaginatedPerPage"
show-total
show-elevator
show-sizer
prev-text="Previous"
next-text="NeXT"/>
</template>
<script>
export default {
props: {
meta : {
type: Object ,
required : true
},
changePaginatedPage : {
type: [Object , Function]
},
changePaginatedPerPage : {
type: [Object , Function]
},
}
}
</script>
Use it in your project like this >>
<Pagination :meta="filterString"
:changePaginatedPage="changePaginatedPage"
:changePaginatedPerPage="changePaginatedPerPage" />
[...]
import {mapState, mapActions, mapMutations, mapGetters } from 'vuex'
export default {
name : "viewCategoriesComponent",
components:{Pagination},
computed: {
...mapState("categoriesStoreIndex", [ 'showEditModal' , 'editData','isLoading' , 'isEditing','errors' ,'multiSelected' ]),
...mapGetters("categoriesStoreIndex",['getAllCategory','filterString' ])
},
methods:{
...mapActions("categoriesStoreIndex", ['changePaginatedPage','changePaginatedPerPage']),
}
}
[...]
Reusable FilterData.vue File
<template>
<Card translate="bn" type="primary">
<Row>
<Col span="5" class="mr-2">
<form class="form-inline ml-3 mb-4" @submit.prevent="getResult">
<div class="input-group input-group-sm">
<input class="form-control form-control-navbar" type="search" placeholder="Search" aria-label="Search" v-model="defaultFilter.q" >
<div class="input-group-append">
<button class="btn btn-navbar" type="submit">
<i class="fas fa-search"></i>
</button>
</div>
</div>
</form>
</Col>
<Col span="5" class="mr-2">
<i-select v-model="defaultFilter.orderBy" style="width:200px">
<i-option v-for="item in orderList" :value="item.value" :key="item.value">{{ item.label }}</i-option>
</i-select>
</Col>
<Col span="5" class="mr-2">
<Select v-model="defaultFilter.sortBy" >
<Option v-for="(sort,i) in SortList" :key="i" :value="sort.value"> {{ sort.label }} </Option>
</Select>
</Col>
<Col span="5" class="mr-2">
<Select v-model="defaultFilter.perPage">
<Option v-for="(per,i) in perPageList" :key="i" :value="per.value"> {{ per.label }} </Option>
</Select>
</Col>
<Col span="3">
<Button type="default" @click="getResult" icon="ios-settings"> Filter </Button>
</Col>
</Row>
</Card>
</template>
<script>
export default {
name : "FilterData" ,
props:{
defaultFilter: Object,
getResult: [Function]
},
data(){
return {
perPageList : [{
label : "5 Per Page" ,
value : 5
},
{
label : "10 Per Page" ,
value : 20
},
{
label : "20 Per Page" ,
value : 20
},
{
label : "30 Per Page" ,
value : 30
},
{
label : "40 Per Page" ,
value : 40
},
{
label : "50 Per Page" ,
value : 50
},
{
label : "80 Per Page" ,
value : 80
},
{
label : "100 Per Page" ,
value : 100
},
{
label : "200 Per Page" ,
value : 200
}],
orderList : [{ label : "ID" ,value : "id" },
{label : "Name" ,value : "name" },
{ label : "Date" ,value : "created_at"}],
SortList : [{
label : "Ascending" ,
value : "asc"
},
{
label : "Descending" ,
value : "desc"
}]
}
}
}
</script>
Categories.vue
<template>
<div class="content bg-transparent">
<div class="container-fluid">
<filter-data
:defaultFilter="filterString"
:getResult="getCategories" ></filter-data>
<!--~~~~~~~ TABLE ONE ~~~~~~~~~-->
<div class="card p-2">
<p class="card-title ml-3">Categories
<!-- adding modal -->
<add-modal-component v-if="isPermitted('create','category')"></add-modal-component> </p>
<div class="card-body">
<view-categories-component v-if="isPermitted('view','category')"></view-categories-component>
</div>
<!-- edit Modal -->
<edit-modal-component v-if="isPermitted('update','category')"></edit-modal-component>
</div>
</div>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import addModalComponent from "../component/addModalComponent"
import editModalComponent from "../component/editModalComponent"
import viewCategoriesComponent from '../component/viewCategoriesComponent';
import FilterData from '../component/FilterData';
export default {
components: {
addModalComponent,
editModalComponent,
viewCategoriesComponent,
FilterData
},
computed: {
...mapGetters("categoriesStoreIndex",['filterString' ])
},
methods:{
...mapActions("categoriesStoreIndex", ['getCategories'])
}
}
</script>
Now Preparing project for Localization & Translating
Run this npm command
'npm install vue-i18n vuex-persistedstate'
PHP Artisan Clear Commands
php artisan config:clear && php artisan route:clear && php artisan view:clear