Last active
August 15, 2019 12:56
-
-
Save renalpha/b82abbf55d6886daabe4d9c563d975af to your computer and use it in GitHub Desktop.
DataComponent for Laravel-Vue-Pagination
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Queries; | |
use Spatie\QueryBuilder\QueryBuilder; | |
abstract class AbstractQuery extends QueryBuilder | |
{ | |
/** | |
* @var array | |
*/ | |
protected $filters = []; | |
/** | |
* @var array | |
*/ | |
protected $columns = []; | |
/** | |
* @param array $filters | |
* @throws \Exception | |
*/ | |
protected function validateFilters(array $filters) | |
{ | |
$requiredKeys = [ | |
'type', | |
'title', | |
]; | |
$errors = []; | |
foreach ($filters as $filter) { | |
foreach ($requiredKeys as $key) { | |
if (!array_key_exists($key, $filter)) { | |
$errors[$key] = 'Filter ' . $key . ' parameter does not exists.'; | |
} | |
} | |
} | |
if (count($errors) > 0) { | |
throw new \Exception(implode(', ', $errors)); | |
} | |
} | |
/** | |
* @param array $filters | |
* @return \App\Queries\AbstractQuery | |
* @throws \Exception | |
*/ | |
public function setFilters(array $filters) | |
{ | |
$this->validateFilters($filters); | |
$this->allowedFilters(array_keys($filters)); | |
$this->filters = $filters; | |
return $this; | |
} | |
/** | |
* @param array $columns | |
* @return \App\Queries\AbstractQuery | |
*/ | |
public function setColumns(array $columns) | |
{ | |
$this->columns = $columns; | |
return $this; | |
} | |
/** | |
* @return array | |
*/ | |
public function getFilters() | |
{ | |
return ['filters' => $this->filters]; | |
} | |
/** | |
* @return array | |
*/ | |
public function getColumns() | |
{ | |
return ['columns' => $this->filters]; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div> | |
<template v-for="(filters) in chunkedFilters"> | |
<div class="row"> | |
<div class="col-md-3" v-for="(value) in filters"> | |
<div class="form-group"> | |
<label>{{ value.title }}</label> | |
<input type="text" v-model="filter['filter['+value.key+']']" class="form-control" | |
@input="debounceInput" v-if="value.type === 'text'"/> | |
<select v-model="filter['filter['+value.key+']']" v-else-if="value.type === 'select'" | |
@input="debounceInput" class="form-control"> | |
<option :value="undefined">-- Select --</option> | |
<option v-for="(value, key) in value.data" :value="key" :selected="value === ''"> | |
{{ value }} | |
</option> | |
</select> | |
</div> | |
</div> | |
</div> | |
</template> | |
<div class="clearfix"></div> | |
<div class="float-right"> | |
<pagination :data="dataResource" :limit="4" :show-disabled="true" @pagination-change-page="getResults"> | |
<span slot="prev-nav">< Previous</span> | |
<span slot="next-nav">Next ></span> | |
</pagination> | |
</div> | |
<div class="float-left"> | |
<p><span><strong>Total products:</strong> {{ dataResource.total }} | <strong>Per page:</strong> {{ dataResource.per_page }}</span> | |
</p> | |
</div> | |
<div class="clearfix"></div> | |
<div class="table-responsive"> | |
<table class="table table-striped table-condensed"> | |
<thead> | |
<tr> | |
<template v-for="(value, key) in columns"> | |
<th> | |
<a href="#" @click="sortBy(key)" v-if="sorts.includes(key) === true"> | |
{{ value }} | |
</a> | |
<span v-else>{{ value }}</span> | |
</th> | |
</template> | |
</tr> | |
</thead> | |
<tbody> | |
<tr v-for="data in dataResource.data"> | |
<template v-for="(value, key) in columns"> | |
<td> | |
<router-link v-bind:to="data['detail_url']" v-if="isLinkedItem(key)"> | |
{{ data[key] }} | |
</router-link> | |
<span v-html="data[key]" v-else="!isLinkedItem(key)">{{ data[key] }}</span></td> | |
</template> | |
</tr> | |
</tbody> | |
</table> | |
</div> | |
<div class="clearfix"></div> | |
<div class="float-left"> | |
<pagination :data="dataResource" :limit="4" :show-disabled="true" @pagination-change-page="getResults"> | |
<span slot="prev-nav">< Previous</span> | |
<span slot="next-nav">Next ></span> | |
</pagination> | |
</div> | |
<div class="float-right"> | |
<p><span><strong>Total products:</strong> {{ dataResource.total }} | <strong>Per page:</strong> {{ dataResource.per_page }}</span> | |
</p> | |
</div> | |
<div class="clearfix"></div> | |
</div> | |
</template> | |
<script> | |
import _ from 'lodash'; | |
export default { | |
mounted() { | |
}, | |
props: { | |
path: { | |
type: String, | |
default: '' | |
}, | |
linked: { | |
default: function () { | |
return ['id'] | |
} | |
}, | |
}, | |
data() { | |
return { | |
// Our data object that holds the Laravel paginator data | |
dataResource: { | |
total: 0, | |
}, | |
search: null, | |
filter: {}, | |
sorts: {}, | |
columns: {}, | |
queryUrl: null, | |
sortAsc: true, | |
column: null, | |
} | |
}, | |
created() { | |
}, | |
mounted() { | |
this.getResults(); | |
}, | |
computed: { | |
chunkedFilters() { | |
return _.chunk(_.map(this.dataResource.filters, (value, key) => ({ | |
key, | |
...value | |
})), 4); | |
} | |
}, | |
methods: { | |
getResults(page = 1) { | |
let path = this.setQuery(page); | |
this.query(path) | |
}, | |
setQuery(page = 1) { | |
let path = this.path + '?page=' + page; | |
if (Object.keys(this.filter).length !== 0) { | |
path += '&' + decodeURIComponent(this.serialize(this.filter)); | |
} | |
if (this.column !== null) { | |
path += '&sort=' + this.column; | |
} | |
return path; | |
}, | |
searchNow() { | |
this.removeEmptyFilterValues(this.filter); | |
let path = this.setQuery(); | |
this.query(path) | |
}, | |
sortBy(column) { | |
this.sortAsc = !this.sortAsc; | |
if (this.sortAsc === true) { | |
column = '-' + column; | |
} | |
this.column = column; | |
this.searchNow(); | |
}, | |
query(url) { | |
this.queryUrl = url; | |
axios.get(url) | |
.then(response => { | |
this.dataResource = response.data; | |
this.sorts = this.dataResource.sorts; | |
this.columns = this.dataResource.columns; | |
}); | |
}, | |
isLinkedItem(n) { | |
return this.linked.indexOf(n) > -1 | |
}, | |
debounceInput: _.debounce(function (e) { | |
this.searchNow(); | |
}, 400), | |
serialize(obj) { | |
var str = []; | |
for (var p in obj) | |
if (obj.hasOwnProperty(p)) { | |
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); | |
} | |
return str.join("&"); | |
}, | |
removeEmptyFilterValues(obj) { | |
Object.keys(obj).forEach(function (key) { | |
if (obj[key] && typeof obj[key] === 'object') { | |
this.removeEmptyFilterValues(obj[key]) | |
} else if (obj[key] === null || obj[key] === undefined) { | |
delete obj[key] | |
} | |
}); | |
}, | |
} | |
} | |
</script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* List of all theses available for this student. | |
* | |
* @param \Illuminate\Http\Request $request | |
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View | |
* @throws \Exception | |
*/ | |
public function index(Request $request) | |
{ | |
$thesisQuery = (new ThesisQuery(auth() | |
->user() | |
->theses() | |
->getQuery())) | |
->setFilters([ | |
'title' => ['type' => 'text', 'title' => 'Title'], | |
'status' => ['type' => 'text', 'title' => 'Status'], | |
'academic_year' => ['type' => 'text', 'title' => 'Academic year'], | |
'created_at' => ['type' => 'text', 'title' => 'Created at'], | |
'updated_at' => ['type' => 'text', 'title' => 'Updated at'], | |
]) | |
->setColumns([ | |
'title' => 'Title', | |
'name' => 'Name', | |
'academic_year' => 'Academic year', | |
'status' => 'Status', | |
'created_at' => 'Created at', | |
'updated_at' => 'Updated at', | |
]); | |
if ($request->wantsJson()) { | |
return response() | |
->json($thesisQuery->paginate(self::DEFAULT_PAGINATE_SIZE)->toArray() + $thesisQuery->getColumns() + $thesisQuery->getFilters() + ['title' => 'Theses']); | |
} | |
return abort(403); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Queries; | |
use App\Models\Thesis; | |
final class ThesisQuery extends AbstractQuery | |
{ | |
/** | |
* ThesisQuery constructor. | |
* | |
* @param null $builder | |
*/ | |
public function __construct($builder = null) | |
{ | |
parent::__construct($builder ?? Thesis::query()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage
npm install laravel-vue-pagination
<data-component path="/json-url-api-pagination" :columns="json_encode(['title','created_at'])></data-component>