我正在使用vuetify作为我的数据表。分页和排序正在工作,但搜索过滤器除外。搜索过滤器的响应数据是正确的,但问题是它没有呈现对我的模板的响应。在vuetify文档中,只有分页和排序。我试图通过服务器端实现搜索功能。
我的User.vue
export default{
data () {
return {
max25chars: (v) => v.length <= 25 || 'Input too long!',
tmp: '',
search: '',
totalItems: 0,
pagination: {
rowsPerPage: 1,
search: ''
},
headers: [
{
text: 'Name',
sortable: true,
value: 'name',
align: 'left'
},
{
text: 'Email Add',
sortable: true,
value:'email',
align: 'left'
},
{
text: 'Roles',
sortable: true,
value:'roles_permissions',
align: 'left'
},
{
text: 'Date joined',
sortable: true,
value:'created_at',
align: 'left'
}
],
items: [],
loading: false,
timer: null
}
},
watch:{
pagination:{
handler(){
this.getDataFromApi()
.then(data => {
const self = this;
self.items = data.items;
self.totalItems = data.total;
})
},
deep: true
}
},
mounted(){
this.getDataFromApi()
.then(data => {
this.items = data.items;
this.totalItems = data.total;
});
},
methods:{
getDataFromApi(search_val){
this.loading = true;
return new Promise((resolve, reject) => {
const { sortBy, descending, page, rowsPerPage } = this.pagination
const search = this.search;
//console.log(search);
clearTimeout(this.timer);
this.timer = setTimeout(function(){
axios({
url: '/prod/api/user_table',
method:'post',
data:{
sortBy : sortBy,
descending: descending,
page : page,
rowsPerPage : rowsPerPage,
search_val : search
}
})
.then(response=>{
if(response.status == 200){
let items = response.data.data;
const total = response.data.totalRecords;
this.loading = false;
resolve({
items,
total
});
}
})
.catch(error=>{
if(error.response){
console.log(error.response);
}
})
},1000);
})
},
fetchDataFromApi(value){
//console.log(value);
}
},
created(){
}
}
这是我的后端使用laravel
public function dataTable(Request $request){
//return Datatable::eloquent(User::query())->make(true);
$sortBy = $request->sortBy;
$descending = $request->descending;
$page = $request->page;
$rowsPerPage = $request->rowsPerPage;
$search_val = $request->search_val;
//echo $rowsPerPage;
if($descending){
$orderedBy = 'desc';
}else{
$orderedBy = 'asc';
}
$start = ($page - 1) * $rowsPerPage;
/*$totalRec = User::all();
if(empty(trim($search_val))){
$user = User::orderBy($sortBy,$orderedBy)->skip($start)->take($rowsPerPage)->get();
}else{
$user = User::where([
]);
}*/
$query = User::query();
$column = ['name', 'email'];
foreach ($column as $col) {
$query->orWhere($col, 'LIKE','%'.$search_val.'%');
}
$query->orderBy($sortBy,$orderedBy)->skip($start)->take($rowsPerPage);
$arr_items = [];
foreach ($query->get()->toArray() as $shit => $v) {
$arr_items['data'][] = array(
'value' => $v['id'],
'name' => $v['name'],
'email' => $v['email'],
'roles_permissions' => '',
'created_at' => $v['created_at']
);
}
$arr_items['totalRecords'] = User::count();
return response()->json($arr_items);
}
答案 0 :(得分:5)
如果我们需要 vuetify.js datatable 中的服务器端搜索和排序,我们必须在vuejs部分进行一些更改。
import {environment} from '../../environment';
export default {
name: "Category",
data() {
return {
categories: [],
search: '',
total: 0,
loading: false,
pagination: {},
headers: [
{text: 'ID', value: 'id'},
{text: 'Name', value: 'name'},
{text: 'Actions', value: 'name', sortable: false, align: 'center'}
],
rowsPerPageItems: [5, 10, 20, 50, 100],
}
},
watch: {
pagination {
this.getCategoriesByPagination();
},
search() {
this.getCategoriesByPagination();
}
},
methods: {
getCategoriesByPagination() {
this.loading = true;
// get by search keyword
if (this.search) {
axios.get(`${environment.apiUrl}/category-filter?query=${this.search}&page=${this.pagination.page}&per_page=${this.pagination.rowsPerPage}`)
.then(res => {
this.categories = res.data.data;
this.total = res.data.meta.total;
})
.catch(err => console.log(err.response.data))
.finally(() => this.loading = false);
}
// get by sort option
if (this.pagination.sortBy && !this.search) {
const direction = this.pagination.descending ? 'desc' : 'asc';
axios.get(`${environment.apiUrl}/category-order?direction=${direction}&sortBy=${this.pagination.sortBy}&page=${this.pagination.page}&per_page=${this.pagination.rowsPerPage}`)
.then(res => {
this.loading = false;
this.categories = res.data.data;
this.total = res.data.meta.total;
});
} if(!this.search && !this.pagination.sortBy) {
axios.get(`${environment.apiUrl}/category?page=${this.pagination.page}&per_page=${this.pagination.rowsPerPage}`)
.then(res => {
this.categories = res.data.data;
this.total = res.data.meta.total;
})
.catch(err => console.log(err.response.data))
.finally(() => this.loading = false);
}
}
}
}
html 部分中的
<v-text-field v-model="search"
append-icon="search"
label="Search"
single-line
hide-details
></v-text-field>
<v-data-table :headers="headers"
:items="categories"
:pagination.sync="pagination"
:total-items="total"
:rows-per-page-items="rowsPerPageItems"
:loading="loading"
></v-data-table>
在 Laravel 部分中,我使用了laravel scout
个包。
控制器
/**
* Get category
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
*/
public function getAll()
{
$per_page = empty(request('per_page')) ? 10 : (int)request('per_page');
$categories = Category::latest()->paginate($per_page);
return CategoryResource::collection($categories);
}
/**
* Get category by search results
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
*/
public function getBySearch()
{
$per_page = empty(request('per_page')) ? 10 : (int)request('per_page');
$categories = Category::search(request()->query('query'))->paginate($per_page);
return CategoryResource::collection($categories);
}
/**
* Get category by sorting
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
*/
public function getByOrder()
{
$per_page = empty(request('per_page')) ? 10 : (int)request('per_page');
$direction = request()->query('direction');
$sortBy = request()->query('sortBy');
$categories = Category::orderBy($sortBy, $direction)->paginate($per_page);
return CategoryResource::collection($categories);
}
路线
Route::get('category', 'Api\CategoryController@getAll');
Route::get('category-filter', 'Api\CategoryController@getBySearch');
Route::get('category-order', 'Api\CategoryController@getByOrder');
模型
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Category extends Model
{
use Searchable;
/**
* Get the indexable data array for the model.
*
* @return array
*/
public function toSearchableArray()
{
return [
'name' => $this->name
];
}
}
答案 1 :(得分:1)
要启用服务器端搜索,请不要将搜索属性传递给v-data-table。否则,即使您通过了“ totalItems”道具,数据表的分页和搜索仍是客户端。
答案 2 :(得分:1)
您可以通过搜索道具,但初始值必须为null。我首先用一个空字符串尝试了它,但至少在我看来,它没有用。
答案 3 :(得分:1)
<template>
<div class="data-table">
<v-data-table :headers="headers" :items="desserts" :items-per-page="5" :options.sync="options" :server-items-length="totalDesserts" :loading="loading" class="elevation-1" ></v-data-table>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import axios from 'axios'
import { api } from '~/config'
import Form from '~/mixins/form'
export default {
data: () => ({
desserts_s: [],
totalDesserts: 0,
loading: true,
options: {},
headers: [
{ text: 'id', value: 'id' },
{ text: 'lastname', value: 'lastname' },
{ text: 'email', value: 'email' },
],
desserts: [],
}),
watch: {
options: {
handler () {
this.getDataFromApi()
.then(data => {
this.desserts = data.items
this.totalDesserts = data.total
})
},
deep: true,
},
},
mounted () {
this.getDataFromApi()
.then(data => {
this.desserts = data.items
this.totalDesserts = data.total
})
},
methods: {
getDataFromApi () {
this.loading = true
return new Promise((resolve, reject) => {
const { sortBy, sortDesc, page, itemsPerPage } = this.options
axios.get(api.path('test')+"?"+Object.keys(this.options).map(key => key + '=' + this.options[key]).join('&'))
.then((response) => {
let items = response.data.users.data
const total = response.data.users.total
console.log(response.data.users.data)
if (sortBy.length === 1 && sortDesc.length === 1) {
items = items.sort((a, b) => {
const sortA = a[sortBy[0]]
const sortB = b[sortBy[0]]
if (sortDesc[0]) {
if (sortA < sortB) return 1
if (sortA > sortB) return -1
return 0
} else {
if (sortA < sortB) return -1
if (sortA > sortB) return 1
return 0
}
})
}
this.loading = false
resolve({
items,
total,
})
})
.catch((error) => console.log(error.message))
})
},
getDesserts () {
},
},
}
</script>
答案 4 :(得分:0)
你应该使用计算
我正在使用服务器分页和搜索。你可以检查我的代码
<template>
<v-card flat>
<v-data-table
:headers="tableHead"
:items="computedFormData.items"
v-if="computedFormData && computedFormData.items"
:mobile-breakpoint="820"
v-model="selected"
:show-select="true"
:loading="loading"
:form-data="formData"
@update:page="getItemPerPage"
@update:items-per-page="getItemPerPage2"
:server-items-length="paginationTotal"
:schema="schema"
:search="search"
>
<template v-slot:top>
<v-toolbar flat color="white">
<v-toolbar-title class="mr-4" v-if="addHeading">{{ addHeading }}</v-toolbar-title>
</v-toolbar>
</template>
</v-data-table>
</v-card>
</template>
<script>
import {mapMutations, mapGetters, mapActions} from 'vuex'
export default {
name: 'DataTable',
components: { Button, Tab: () => import('@/components/Tabs'), Dialog: () => import('@/components/Dialog'), TableFormBuilder: () => import('@/components/Form/TableFormBuilder'), FormBuilder: () => import('@/components/Form/FormBuilder') },
props: [
'schema',
'formData',
'name',
'itemsTab',
'value',
'headers',
'title',
'nodata',
'addHeading',
'confirmDeleteTabItem',
'tableTitleOptionA',
'tableTitleOptionB',
'items'
],
data: () => ({
loading: false,
selected: [],
companyValid: true,
customerValid: true,
search: '',
dialog: false,
editedIndex: -1,
editedItem: {},
defaultItem: {}
}),
computed: {
...mapGetters('Connection', ['getConnectionPending', 'getAddFirm', 'getUpdateFirm', 'getDeleteFirm', 'getMultipleDeleteFirm', 'getCompanies']),
...mapGetters('Pagination', ['getPage']),
tableHead(){
return this.headers.filter(s => s.show);
},
computedFormData: {
get: function () {
return this.$parent.formData
},
set: function () {
return this.formData
}
},
paginationTotal: {
get: function () {
return this.$parent.formData.totalLength
}
},
tabItems: {
get: function () {
if(this.search!==''){
return this.$parent.formData.items.filter(s => s.firmaAdi === this.search)
}else{
return this.$parent.formData.items
}
},
set: function () {
return this.items
}
},
formTitle () {
return this.editedIndex === -1
? this.tableTitleOptionA
: this.tableTitleOptionB
}
},
methods: {
...mapActions("Snackbar", ["setSnackbar"]),
...mapActions("Connection", ["addFirmCall", "updateFirmCall", "deleteFirmCall", "multipleDeleteCall", "companiesCall"]),
...mapMutations('Selected', ['setSelected']),
...mapMutations('Pagination', ['setPage']),
getItemPerPage (pagination) {
this.loading=true;
this.setPage(pagination)
},
getItemPerPage2 (pagination) {
this.loading=true;
this.setPage(pagination)
},
},
watch: {
getConnectionPending(e){
this.loading=e
},
dialog(val) {
val || this.close();
},
search(e){
this.companiesCall({ page: this.getPage, limit: 10, search: e});
},
selected(e){
this.setSelected(e)
}
},
}
</script>
答案 5 :(得分:-1)
迟到了,但我最近一直在寻找与yajra/laravel-datatables相似的东西,但没有找到任何示例/库,因此创建了一个可行的东西:
composer require yajra/laravel-datatables-oracle:"~9.0"
(并按照有关如何添加Provider, Facade, config
的说明进行操作use DataTables;
------
public function dataTable(Request $request){
//one line of code for simple search /sort / pagination
return DataTables::of(User::query())->make(true);
}
Vuetify
组件<template>
<v-data-table
:headers="headers"
:items="users"
:pagination.sync="pagination"
:total-items="totalUsers"
:rows-per-page-items="rowsPerPageItems"
:loading="loading"
>
<template v-slot:items="props">
<tr>
<td>
<div class="d-flex">
<v-btn :to="{ name: 'users.edit', params: { id: props.item.id }}">Edit</v-btn>
</div>
</td>
<td>{{ props.item.id }}</td>
<td>{{ props.item.name }}</td>
<td>{{ props.item.email }}</td>
</tr>
</template>
<template v-slot:no-results>
<v-alert :value="true" color="error" icon="warning">
Your search for "{{ searchQuery }}" found no results.
</v-alert>
</template>
</v-data-table>
</template>
<script>
import axios from 'axios';
export default {
data () {
return {
draw: 1,
users: [],
searchQuery: "",
loading: true,
pagination: {
descending: true,
page: 1,
rowsPerPage: 10,
sortBy: "id",
totalItems: 0
},
totalUsers: 0,
rowsPerPageItems: [10, 15, 20, 30, 40, 50],
columns:{},
headers: [
{ text: 'Actions', value: 'actions', sortable: false, searchable: false, width: '210px'},
{ text: 'ID', value: 'id', name: 'id', sortable: true, searchable: true, width: '40px'},
{ text: 'Name', value: 'name', name: 'name', sortable: true, searchable: true, width: '250px'},
{ text: 'Email', value: 'email', sortable: true, searchable: true, width: '80px'},
],
cancelSource: null
}
},
watch: {
//watcher to watch for order/pagination and search criteria.
//
params: {
handler() {
//on params change refetch Data
//We don't do it in mounted method, becuase on first load params will change.
this.getDataFromApi().then(data => {
this.users = data.items;
this.totalUsers = data.total;
});
},
deep: true
}
},
mounted() {
//Based on our Headers we create query data for DataTables
//I've added a new param "searchable" to let DataBales know that this column is not searchable
//You can also set name as "table.column eg users.name" if you select from more then table to avoid "Ambitious column name error from SQL"
for (var i = 0; i < this.headers.length; i++) {
this.columns[i] = {
data: this.headers[i].value,
name: (typeof(this.headers[i].name) != 'undefined' ? this.headers[i].name : this.headers[i].value),
searchable: this.headers[i].searchable,
orderable: this.headers[i].sortable,
search: {
value: '',
regex: false
}
};
}
},
//computed params to return pagination and search criteria
computed: {
params(nv) {
return {
...this.pagination,
query: this.searchQuery
};
}
},
methods: {
cancelRequest() {
//Axios cancelSource to stop current search if new value is entered
if (this.cancelSource) {
this.cancelSource.cancel('Start new search, stop active search');
}
},
getDataFromApi() {
//show loading of Vuetify Table
this.loading = true;
return new Promise((resolve, reject) => {
this.cancelRequest();
this.cancelSource = axios.CancelToken.source();
//copy current params to modify
let params = this.params;
params.length = params.rowsPerPage; //set how many records to fecth per page
params.start = params.page == 1 ? 0 : (params.rowsPerPage * (params.page - 1)); //set offset
params.search = {
value: params.query,
regex: false
}; //our search query
params.draw = this.draw;
//sorting and default to column 1 (ID)
if(params.sortBy){
params.order = {
0: {
column: _.findIndex(this.headers, {
'value': params.sortBy
}),
dir: (params.descending ? 'desc' : 'asc')
}
};
}else{
params.order = {
0: {
column: 1,
dir: 'desc'
}
};
}
params.columns = this.columns; //set our previously created columns
//fecth data
//I used here jQuery $.param() helper, becuase axios submits data as JSON Payload, and we need for data or Query params
//This can be changed
axios.get('/users?'+$.param(params), {
cancelToken: this.cancelSource.token
}).then((res) => {
this.draw++;
this.cancelSource = null;
let items = res.data.data;
let total = res.data.recordsFiltered;
resolve({
items,
total
});
}).catch((err) => {
if (axios.isCancel(err)) {
console.log('Request canceled', err.message);
} else {
reject(err);
}
}).always(() => {
this.loading = false;
});
});
}
}
}
</script>
一个简单的解决方案,可以使vuetify与Laravel DataTables一起工作,当然这不是理想的方法,但是效果很好。希望对您有所帮助。