Vue.js sorting is not working when fetching from Laravel - laravel

Currently this is for listing customer data from database. Data is fetching using Laravel 5. At present data is fetching and listing properly. This page contains pagination, filter search and sorting functionality. My problem is sorting is not working properly. Could you please help me to sort out this issue? I am using Vue.js version 1.0.25
Here is the short code, only the sorting part
View
<th v-for="key in columns" #click="sortBy(key)" :class="{active: sortKey == key}">
#{{ colTitles[key] }}
</th>
<tr v-for="(index, item) in items | filterBy searchQuery | orderBy sortKey reverse">
........
JS
data: {
sortKey: '',
reverse: false,
.........
sortBy: function(sortKey) {
this.reverse = (this.sortKey == sortKey) ? ! this.reverse : false;
this.sortKey = sortKey;
}
Full code
dashboard.blade.php
<div class="container">
<div class="row">
<h1 class="page-header">{{ trans('messages.customerListPageHeadingLabel') }}</h1>
<div id="app">
<div class="form-group col-md-4">
<form id="search" class="form-inline">
<label for="query">{{ trans('messages.customerListPageSearchBox') }} </label>
<input name="query" class="form-control" v-model="searchQuery">
</form>
</div>
<br>
<table class="table table-hover table-bordered">
<thead>
<tr>
<th v-for="column in columns" #click="sortBy(column)">
#{{ colTitles[column] }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(index, item) in items | filterBy searchQuery | orderBy sortKey reverse">
<td>#{{ item.erp_id }}</td>
<td>#{{item.firstname}}</td>
<td>#{{item.lastname}}</td>
<td>#{{item.email}}</td>
<td>#{{item.phone_1}}</td>
<td>#{{item.status}}</td>
<td>#{{item.created_on}}</td>
</tr>
</tbody>
</table>
<nav>
<ul class="pagination">
<li v-if="pagination.current_page > 1">
<a href="#" aria-label="Previous"
#click.prevent="changePage(pagination.current_page - 1)">
<span aria-hidden="true">«</span>
</a>
</li>
<li v-for="page in pagesNumber"
v-bind:class="[ page == isActived ? 'active' : '']">
<a href="#"
#click.prevent="changePage(page)">#{{ page }}</a>
</li>
<li v-if="pagination.current_page < pagination.last_page">
<a href="#" aria-label="Next"
#click.prevent="changePage(pagination.current_page + 1)">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
Laravel Controller
public function listCustomers()
{
$results = Customer::select('id', 'erp_id', 'firstname', 'lastname', 'email', 'phone_1', 'status', DB::raw("DATE_FORMAT(created_at, '%d.%m.%Y %H:%i') AS created_on"))
->orderBy('id', 'desc')->latest()->paginate(25);
$response = [
'pagination' => [
'total' => $results->total(),
'per_page' => $results->perPage(),
'current_page' => $results->currentPage(),
'last_page' => $results->lastPage(),
'from' => $results->firstItem(),
'to' => $results->lastItem()
],
'data' => $results
];
return $response;
}
Vue JS
new Vue({
el: '#app',
data: {
sortKey: '',
reverse: false,
columns: ['erp_id', 'firstname', 'lastname', 'email', 'phone_1', 'status', 'created_on'],
colTitles: {'erp_id':'#lang('messages.customerListPageTableCustomerNo')', 'firstname':'#lang('messages.customerListPageTableFirstname')', 'lastname':'#lang('messages.customerListPageTableLastname')', 'email':'E-Mail', 'phone_1':'#lang('messages.customerListPageTablePhone')', 'status':'Status', 'created_on':'#lang('messages.customerListPageTableAddedDate')'},
pagination: {
total: 0,
per_page: 7,
from: 1,
to: 0,
current_page: 1
},
offset: 4,// left and right padding from the pagination <span>,just change it to see effects
items: []
},
ready: function () {
this.fetchItems(this.pagination.current_page);
},
computed: {
isActived: function () {
return this.pagination.current_page;
},
pagesNumber: function () {
if (!this.pagination.to) {
return [];
}
var from = this.pagination.current_page - this.offset;
if (from < 1) {
from = 1;
}
var to = from + (this.offset * 2);
if (to >= this.pagination.last_page) {
to = this.pagination.last_page;
}
var pagesArray = [];
while (from <= to) {
pagesArray.push(from);
from++;
}
return pagesArray;
}
},
methods: {
fetchItems: function (page) {
var data = {page: page};
this.$http.get('/list/customers', data).then(function (response) {
//look into the routes file and format your response
this.$set('items', response.data.data.data);
this.$set('pagination', response.data.pagination);
}, function (error) {
// handle error
});
},
changePage: function (page) {
this.pagination.current_page = page;
this.fetchItems(page);
},
sortBy: function(sortKey) {
this.reverse = (this.sortKey == sortKey) ? ! this.reverse : false;
this.sortKey = sortKey;
}
}
});

the last parameter of orderBy should be 1 or -1, while you provide either true or false with the value of reverse
https://jsfiddle.net/Linusborg/spwwxLvy/
change this:
this.reverse = (this.sortKey == sortKey) ? ! this.reverse : false;
to this:
this.reverse = (this.sortKey == sortKey) ? 1 : -1;
also change the initial value in data() accordingly.

Related

Anyone can tell me whats wrong in here when im putting a array of number like :1,2 its starting to freeze the screen i hope someone can help me thanks

Hello guys im trying to learn vue and im trying to use datatable from https://datatables.net/ and having a problem with my action button that im not able to get the id when the #viewModal is been triggered i hope someone can help me to get the id of each buttons thanks and here is my code TIA:
EmployeeDataTable Component :
<template>
<div class="card">
<div class="card-header">
<div class="card-title">Employee List</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table
id="employee-table"
class="table-sm table-bordered table-hover text-center display"
width="100%"
>
<thead>
<tr>
<th class="pt-3 pb-3">#</th>
<th>Name</th>
<th>Address</th>
<th>Contact #</th>
<th>Department</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
</template>
<script>
//For Datatable to work
import "datatables.net";
import EmployeeEdit from "./EmployeeEdit.vue";
export default {
name: "EmployeeList",
data() {
return {
employees: [],
};
},
mounted() {
this.getEmployeeLists();
},
components: {
"employee-edit": EmployeeEdit,
},
methods: {
getEmployeeLists() {
// INITIALIZE DATATABLE
$("#employee-table")
.DataTable({
//LOADING
// processing: true,
//AJAX
serverSide: true,
//DIRECTION
order: [[1, "desc"]],
//AJAX
ajax: {
url: "/api/getEmployeeLists",
dataList: "json",
type: "POST",
data: { _token: "{{csrf_token()}}" },
},
//TABLE COLUMNS SHOULD BE THE SAME IN CONTROLLER
columns: [
{ data: "#" },
{ data: "name" },
{ data: "address" },
{ data: "contact" },
{ data: "department" },
{ data: "status" },
{
data: "actions",
//allowing modification
createdCell(cell, cellData, rowData) {
let EmployeeListDataTableActions = Vue.extend(
require("./EmployeeListDataTableAction.vue").default
);
let instance = new EmployeeListDataTableActions().$mount();
$(cell).empty().append(instance.$el);
},
},
],
//View Count in Table
lengthMenu: [
[10, 25, 50, -1],
[10, 25, 50, "All"],
],
})
.columns();
},
beforeDestroy: function () {
$(this.$el).DataTable().destroy();
},
},
};
</script>
EmployeeDataTableAction Component :
<template>
<button class="btn btn-primary btn-sm" #click="viewModal" title="View Employee Details">
<i class="fa fa-eye"></i>
</button>
</template>
<script>
export default{
name: 'EmployeeListDataTableAction',
data: function() {
return {
}
},
mounted() {
},
methods: {
viewModal() {
var id = $(this.$el).closest('tr').find('input').val();
return false;
axios
.post(`/api/getEmployeeDetails/${id}`, {
id: id,
})
.then((response) => {
$("#edit-employee-modal").modal("show");
$(".myModalLabel").text(
response.data.name +
" - " +
response.data.department_name
);
state.commit("getEmployeeDetailsArray", response.data);
state.commit("getTransactionId", response.data.id);
})
.catch((response) => {
this.$toast.top("Something went wrong!");
});
},
},
}
</script>
Employee Controller for the DataTable :
public function employeeList(Request $request){
$all = Employee::getEmployeeTotal();
//total count of data
$total_data = $all;
//total filter
$total_filtered = $total_data;
//set_time_limit(seconds)
$limit = $request->input('length');
//start
$start = $request->input('start');
//order
// $order = $columns[$request->input('order.0.column')];
//direction
$dir = $request->input('order.0.dir');
$search_value = $request->input('search.value');
if (!empty($search_value)) {
$posts = Employee::getEmployeeNameSearch($search_value,$start, $limit, $dir);
$total_data = count($posts);
$total_filtered = $total_data;
}else{
if(empty($request->input('search.value')))
{
//if no search
$posts = Employee::getEmployeeList($start, $limit, $dir);
}
}
$data = array();
if(!empty($posts))
{
$counter = $start + 1;
foreach ($posts as $post)
{
$department = GlobalModel::getSingleDataTable('departments',$post->department_id);
$status = StatusController::checkStatus($post->status);
$nested_data['#'] = '<span style="font-size: 12px ; text-align: center;">'.$counter++.'</span>';
$nested_data['name'] = '<p style="text-align: center;">'.$post->name.'</p>';
$nested_data['address'] = '<p style="text-align: center;">'.$post->address.'</p>';
$nested_data['contact'] = '<p style="text-align: center;">'.$post->contact.'</p>';
$nested_data['department'] = '<p style="text-align: center;">'.$department->name.'</p>';
$nested_data['status'] = '<p style="text-align: center;">'.$status.'</p>';
$nested_data['actions'] = '';
$data[] = $nested_data;
}
}
$json_data=array(
"draw" => intval($request->input('draw')),
"recordsTotal" => intval($total_data),
"recordsFiltered" => intval($total_filtered),
"data" => $data
);
return response()->json($json_data);
}
In the second line of your viewModal() function, you are placing a return false; statement. "The return statement ends function execution and specifies a value to be returned to the function caller." From Mozilla docs. That's why the API call is never executing.

Conditional Component variable value increment Vue/Laravel

[1]so i have a laravel project going on, and i want to increment the value of the variable deliver_later_num, depending on the "deliver_today" present in the same component in the items[] array, which i am outputting in the template file, i cannot figure how to do it, i do not know if i can increment the value on the template side or on the component side. here is the component code:
cartContent = new Vue({
el: '#cartList',
data: {
items: [], //array containing all the items
deliver_later_num: 0, //value to increment
},
methods: {
remove: function (product_id) {
removeProductIfFromCart(product_id);
},
incQuantity: function (product_id){
incCart(product_id)
},
decQuantity: function (product_id){
decCart(product_id)
},
}
})
here is the template file :
<div id="cartList">
<div v-for="item in items" class="items col-xs-12 col-sm-12 col-md-12 col-lg-12 clearfix">
<div class="info-block block-info clearfix" v-cloak>
<div class="square-box pull-left">
<img :src="item.attributes.image" class="productImage" width="100" height="105" alt="">
</div>
<h6 class="product-item_title">#{{ item.name }}</h6>
<p class="product-item_quantity">#{{ item.quantity }} x #{{ item.attributes.friendly_price }}</p>
<ul class="pagination">
<li class="page-item">
<button v-on:click="decQuantity(item.id)" :value="item.id" class="page-link" tabindex="-1">
<i class="fa fa-minus"></i>
</button>
</li>
<li class="page-item">
<button v-on:click="incQuantity(item.id)" :value="item.id" class="page-link" >
<i class="fa fa-plus"></i>
</button>
</li>
<li class="page-item">
<button v-on:click="remove(item.id)" :value="item.id" class="page-link" >
<i class="fa fa-trash"></i>
</button>
</li>
<input hidden class="delivers_today_state" type="text" :value=" item.attributes.delivers_today "> // if this equals 0 i want to increment the deliver_later_num value
</ul>
</div>
</div>
</div>
laravel controller code :
public function add(Request $request){
$item = Items::find($request->id);
$restID=$item->category->restorant->id;
//Check if added item is from the same restorant as previus items in cart
$canAdd = false;
if(Cart::getContent()->isEmpty()){
$canAdd = true;
}else{
$canAdd = true;
foreach (Cart::getContent() as $key => $cartItem) {
if($cartItem->attributes->restorant_id."" != $restID.""){
$canAdd = false;
break;
}
}
}
//TODO - check if cart contains, if so, check if restorant is same as pervious one
// Cart::clear();
if($item && $canAdd){
//are there any extras
$cartItemPrice=$item->price;
$cartItemName=$item->name;
$theElement="";
//Is there a varaint
//variantID
if($request->variantID){
//Get the variant
$variant=Variants::findOrFail($request->variantID);
$cartItemPrice=$variant->price;
$cartItemName=$item->name." ".$variant->optionsList;
//$theElement.=$value." -- ".$item->extras()->findOrFail($value)->name." --> ". $cartItemPrice." ->- ";
}
foreach ($request->extras as $key => $value) {
$cartItemName.="\n+ ".$item->extras()->findOrFail($value)->name;
$cartItemPrice+=$item->extras()->findOrFail($value)->price;
$theElement.=$value." -- ".$item->extras()->findOrFail($value)->name." --> ". $cartItemPrice." ->- ";
}
Cart::add((new \DateTime())->getTimestamp(), $cartItemName, $cartItemPrice, $request->quantity, array('id'=>$item->id,'variant'=>$request->variantID, 'extras'=>$request->extras,'restorant_id'=>$restID,'image'=>$item->icon,'friendly_price'=> Money($cartItemPrice, env('CASHIER_CURRENCY','usd'),true)->format(),'delivers_today' => $item->deliverstoday ));
return response()->json([
'status' => true,
'errMsg' => $theElement
]);
}else{
return response()->json([
'status' => false,
'errMsg' => __("You can't add items from other restaurant!")
]);
//], 401);
}
}
public function getContent(){
//Cart::clear();
return response()->json([
'data' => Cart::getContent(),
'total' => Cart::getSubTotal(),
'status' => true,
'errMsg' => ''
]);
}
link to the items array vue dev tools screenshot
[1]: https://i.stack.imgur.com/smLRV.png
thanks for your precious help and time.
A computed property can be used if the deliver_later_num is only dependent on the presence/absence of deliver_today on elements of items array
cartContent = new Vue({
el: '#cartList',
data: {
items: {}
},
computed: {
deliver_later_num() {
let num = 0;
Object.keys(this.items).forEach(key => {
let item = this.items[key];
Object.keys(item).forEach(k => {
if(k === 'deliver_today' && item[k]) {
num++;
}
});
});
return num;
},
}

I want to show data on chart bar when I search by date wise using Laravel

I have chart bar and I am trying to show data by date wise when I filter by date but unfortunately data does not show on chart bar. I want that when I select a start date and end date record should be shown on chart bar by date wise.
Controller
public function status(Request $request)
{
$date = explode(' - ', $request->date);
$manager_hourlog = Hourlog::with('project', "user")->whereBetween('date', $date)
->get()
->groupBy('project.name');
$projects = [];
$totals = [];
foreach ($manager_hourlog as $key => $val) {
$projects[] = $key;
}
foreach ($manager_hourlog as $key2 => $val) {
$minutes = $val->sum('hour_work');
$totals[] = round($minutes / 60, 1);
}
$users = User::where("status", 1)->get();
$data = [
// manager report
'manager_projects' => $projects,
'totals' => $totals,
"manager_hourlog" => $manager_hourlog,
];
return $data;
return response()->json($data, 200);
}
html view
<form action="{{route('dashboard')}}" method="post" >
<div class="form-group">
<div class="input-group theme-input-group select-max-h-200">
<div class="input-group-prepend width-160px">
<div class="input-group-text">Date
</div>
</div>
<input parsley-trigger="change" required type="text" id="date" class="form-control" name="date" autocomplete="off">
<div class="input-group-append">
<span class="input-group-text">
<i class="md md-event-note">
</i>
</span>
</div>
</div>
<!-- input-group -->
</div>
</div>
<div class="col-lg-1">
<div class="text-right">
<button class="btn btn-light-theme waves-effect waves-light" id="search" name="search" type="submit">
<i class="fa fa-search pr-1">
</i> Search
</button>
</div>
</div>
</form>
script
<script type="text/javascript">
$(function () {
$('#search').on('click', function () {
var date = $("#date").val();
$.ajax({
type: 'GET',
url: '{{Route("dashboard.status")}}',
data: {
date: date
},
dataType: "JSon",
success: function(response){
// Employee report script
var colors = ["#1abc9c", "#2ecc71", "#3498db", "#9b59b6", "#34495e", "#16a085", "#27ae60", "#2980b9", "#8e44ad", "#2c3e50", "#f1c40f", "#e67e22", "#e74c3c", "#ecf0f1", "#95a5a6", "#f39c12", "#d35400", "#c0392b", "#bdc3c7", "#7f8c8d"];
#if ($auth->user_type != 1)
// manager report script
var managerchartbar = {
labels: {!! json_encode($manager_projects) !!},
datasets: [
#foreach($users as $user)
{
label: {!! json_encode($user->name) !!},
backgroundColor: colors[Math.floor(Math.random() * colors.length)],
data: [
#foreach($manager_hourlog as $hourlog)
{{$hourlog->where("user_id", $user->id)->sum("hour_work") / 60}},
#endforeach
]
},
#endforeach
]
};
var ctx = document.getElementById('manager').getContext('2d');
window.myBar = new Chart(ctx, {
type: 'bar',
data: managerchartbar,
options: {
title: {
display: true,
text: 'Project Report chart'
},
tooltips: {
mode: 'index',
intersect: false
},
responsive: true,
scales: {
xAxes: [{
stacked: true,
}],
yAxes: [{
stacked: true
}]
}
}
});
#endif
console.log(response);
},
error: function(xhr){
console.log(xhr.responseText);
}});
});
});
</script>

How to pass updated data to already child vue component rendered

I'm trying to update some vars into a component from parent. My situation is this:
I have a parent component:
import LugarListComponent from './LugarListComponent';
import LugarAddComponent from './LugarAddComponent'
export default {
components:{
'lugar-list-component' : LugarListComponent,
'lugar-add-component' : LugarAddComponent,
},
data(){
return {
show: false,
nombre: '',
desc : '',
}
},
methods:{
showComponent: function () {
this.show = true;
},
hideComponent: function () {
this.show = false;
},
setLugar: function(lugar){
this.show = true;
}
},
mounted() {
//console.log('Component mounted.')
}
}
<template>
<div class="container">
<h3>Lugares</h3>
<div style="text-align: right">
<button type="button" class="btn btn-primary" v-show="!show" v-on:click.prevent="showComponent"><i class="fa fa-plus"></i> Adicionar</button>
<button type="button" class="btn btn-success" v-show="show" v-on:click.prevent="hideComponent"><i class="fa fa-arrow-left"></i> Regresar</button>
</div>
<br>
<lugar-list-component v-show="!show" #setLugar="setLugar"></lugar-list-component>
<lugar-add-component v-show="show" #hideComponent="hideComponent"></lugar-add-component>
</div>
</template>
This component has two childs components, lugar-list for list places and lugar-add for add a place. I have a show var for control when I show one of this.
I want to edit a place, but I want to send data to lugar-add for show his values into this component, but I don't find any solution for update the vars into lugar-add. Here I show the code of this components.
For lugar-add
export default {
data(){
return {
image: '',
nombre: '',
desc : ''
}
},
methods: {
onImageChange(e) {
let files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.createImage(files[0]);
},
createImage(file) {
let reader = new FileReader();
let vm = this;
reader.onload = (e) => {
vm.image = e.target.result;
};
reader.readAsDataURL(file);
},
uploadImage(){
axios.post('/lugar',{
image: this.image,
nombre: this.nombre,
desc: this.desc
}).then(response => {
if(response.status == 200){
this.$emit('hideComponent')
}
});
},
setAttributes(lugarEdit){
console.log('disparado');
this.nombre = lugarEdit.nombre;
this.desc = lugarEdit.desc;
}
},
mounted() {
//console.log('Component mounted.');
this.$on(
'setAttributes',
function(lugar) {
this.nombre = lugar.nombre;
this.desc = lugar.desc;
}
);
}
<template>
<div class="container">
<div class="form-group">
<label>Nombre</label>
<input type="text" v-model="nombre" class="form-control" placeholder="Nombre del lugar">
</div>
<div class="form-group">
<label for="descTexArea">Descripción</label>
<textarea v-model="desc" class="form-control" id="descTexArea" rows="3"></textarea>
</div>
<div class="form-group">
<label for="exampleFormControlFile1">Subir imágenes</label>
<input type="file" v-on:change="onImageChange" class="form-control-file" id="exampleFormControlFile1">
</div>
<div class="form-group">
<button type="button" class="btn btn-primary" #click="uploadImage">Adicionar</button>
</div>
<div class="col-md-3" v-if="image">
<img :src="image" class="img-responsive" height="70" width="90">
</div>
</div>
</template>
Here I use event for hide this component and show the lugar-list component. Here is the code for lugar-list
export default {
name: 'lugar-list-component',
data:function(){
return {
listLugares : [],
id : '',
}
},
methods:{
getLugares: function () {
fetch('/lugar')
.then(response => response.json())
.then(res => {
this.listLugares = res;
})
},
setId: function(id){
this.id = id;
},
removeLugar: function(id){
this.id = id;
axios.delete('lugar/'+id)
.then(response => {
this.getLugares();
});
},
editLugar: function(id){
this.id = id;
axios.get('lugar/'+id)
.then(response => {
this.$emit('setLugar',response);
});
},
},
mounted() {
this.getLugares();
}
}
<template>
<div class="container">
<table class="table table-striped">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Nombre</th>
<th scope="col">Desc.</th>
<th scope="col">Fecha</th>
<th scope="col">Acciones</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in listLugares">
<th scope="row">{{ index+1 }}</th>
<td>{{ item.nombre }}</td>
<td>{{ item.desc }}</td>
<td>{{ item.created_at }}</td>
<td>
<button type="button" class="btn btn-success" v-on:click.prevent="editLugar(item.id)"><i class="fa fa-edit"></i> Editar</button>
<button type="button" class="btn btn-danger" v-on:click.prevent="removeLugar(item.id)"><i class="fa fa-remove"></i> Eliminar</button>
</td>
</tr>
</tbody>
</table>
</div>
</template>
I hope that you can understand me. Thanks.
Emit an event from the 1st child component to update parent's prop. Then pass the value you want to update as a prop to the secund child element.
I don't find other solution that use routes with params, I believe that is the best solution.
Here is my routes
{
path: '/lugar', component: require('./components/lugar/LugarComponent').default,
children: [
{ path: '', component: LugarList },
{
path: 'add/:id?',
name: 'lugarAdd',
component: LugarAdd
},
{
path: 'list',
component: LugarList
}
]
}
The route for Add a place has an optional param.
Now, into the Add component I get the param with this code:
this.id = this.$route.params.id;
this.modeEdit = true;
axios.get('/lugar/'+this.id)
.then(response => {
this.nombre = response.data.nombre;
this.desc = response.data.desc;
for(let i = 0; i<response.data.images.length; i++){
this.image.push(response.data.images[i]);
}
});
When I get the place id I request for its information with axios.

How to sort only the displayed items in table with vue

I have two questions regarding the following code.
1st problem: say I have four items in the array with ids of [1,2,4,5,7]
If I click on the sort and i have 2 items per page chosen then it will show me entries with id's of 1&2 or 5&7 as I toggle the reverse order.
So how can I get the table to just sort the items that are displayed in the paginated view?
2nd problem:
We are using a mixture of vue and some jquery from an admin template we purchased, But where it has <div class="checkbox checkbox-styled"> written in the code the check boxes will not render unless I put the Vue code in a setTimeout with an interval val of '100' or more.
And it generally just doesn't render stuff in jquery well if the item that relies on jquery is in a vue for loop.
Has anyone got an explanation for this?
Please note I've deleted as much out of this to keep the question as small as possible.
<div class="section-body">
<!-- BEGIN DATA TABLE START -->
<form class="form" role="form">
<div class="row">
<div class="col-lg-12">
<div id="" class="dataTables_wrapper no-footer">
<div class="table-responsive">
<table style="width: 100%" cellpadding="3">
<tr>
<td>
<div class="dataTables_length" id="entries_per_page">
<label>
<select name="entries_per_page" aria-controls="datatable" v-model="itemsPerPage">
<option value='2'>2</option>
<option value='20'>20</option>
<option value='30'>30</option>
</select>
entries per page
</label>
</div>
</td>
</tr>
</table>
<table class="table table-striped table-hover dataTable">
<thead>
<tr>
<th>
<div class="checkbox checkbox-styled">
<label>
<input type="checkbox" v-model="selectAll" :checked="allSelected" #click="selectAllCheckboxes">
</label>
</div>
</th>
<th v-bind:class="{'sorting': col.key !== sortKey, 'sorting_desc': col.key == sortKey && !isReversed, 'sorting_asc': col.key == sortKey && isReversed}" v-for="col in columns" #click.prevent="sort(col.key)">
<a href="#" v-cloak>${ col.label | capitalize}</a>
</th>
<th class="text-right">Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items | paginate | filterBy search">
<td width="57">
<div class="checkbox checkbox-styled">
<label>
<input type="checkbox" value="${ item.id }" v-model="cbIds" :checked="cbIds.indexOf(item.id) >= 0" />
</label>
</div>
</td>
<!-- !ENTITY_NAME TABLE COLUMNS START -->
<td v-cloak>${ item.id }</td>
<td v-cloak>${ item.title }</td>
<!-- !ENTITY_NAME TABLE COLUMNS END -->
<td class="text-right">
<button type="button" class="btn btn-icon-toggle" data-toggle="tooltip" data-placement="top" data-original-title="Edit row" #click="editItem(item)">
<i class="fa fa-pencil"></i></button>
<button type="button" class="btn btn-icon-toggle" data-toggle="tooltip" data-placement="top" data-original-title="Delete row" #click="deleteModalOpened(item)">
<i class="fa fa-trash-o"></i>
</button>
</td>
</tr>
</tbody>
</table>
<!-- PAGINATION START -->
<div class="dataTables_info" role="status" aria-live="polite" v-if="resultCount > 0" v-cloak>
Showing ${ currentCountFrom } to ${ currentCountTo } of ${ resultCount } entries
</div>
<div class="dataTables_paginate paging_simple_numbers" id="datatable_paginate" v-if="resultCount > 0">
<a class="paginate_button previous disabled" #click="previousPage()" v-if="currentPage==0">
<i class="fa fa-angle-left"></i>
</a>
<a class="paginate_button previous" #click="previousPage()" v-else>
<i class="fa fa-angle-left"></i>
</a>
<span v-for="pageNumber in totalPages">
<a class="paginate_button current" #click="setPage(pageNumber)" v-show="pageNumber == currentPage" v-cloak>${ pageNumber + 1 }</a>
<a class="paginate_button" #click="setPage(pageNumber)" v-show="pageNumber != currentPage" v-cloak>${ pageNumber + 1 }</a>
</span>
<a class="paginate_button next disabled" #click="nextPage()" v-if="currentPage == (totalPages - 1)">
<i class="fa fa-angle-right"></i>
</a>
<a class="paginate_button previous" #click="nextPage()" v-else>
<i class="fa fa-angle-right"></i>
</a>
</div>
<!-- PAGINATION END -->
</div>
</div>
</div>
</div>
</form>
<!-- BEGIN DATA TABLE END -->
</div>
<script>
Vue.config.delimiters = ['${', '}'];
new Vue({
el: '#app',
data: {
items: [],
columns: [
{
key: 'id' ,
label: 'id' ,
},
{
key: 'title' ,
label: 'title' ,
},
],
// ALL PAGINATION VARS
currentPage: 0,
itemsPerPage: 20,
resultCount: 0,
totalPages: 0,
currentCountFrom: 0,
currentCountTo: 0,
allSelected: false,
cbIds: [],
sortKey: '',
isReversed: false
},
computed: {
totalPages: function() {
return Math.ceil(this.resultCount / this.itemsPerPage);
},
currentCountFrom: function () {
return this.itemsPerPage * this.currentPage + 1;
},
currentCountTo: function () {
var to = (this.itemsPerPage * this.currentPage) + this.itemsPerPage;
return to > this.resultCount ? this.resultCount : to;
}
},
ready: function() {
this.pageUrl = '{{ path('items_ajax_list') }}';
this.getVueItems();
},
filters: {
paginate: function(list) {
this.resultCount = this.items.length;
if (this.currentPage >= this.totalPages) {
this.currentPage = Math.max(0, this.totalPages - 1);
}
var index = this.currentPage * this.itemsPerPage;
return this.items.slice(index, index + this.itemsPerPage);
}
},
methods : {
sort: function (column) {
if (column !== this.sortKey) {
this.sortKey = column;
this.items.sort(this.sortAlphaNum);
this.isReversed = false;
return;
}
this.reverse();
if (this.isReversed) {
this.isReversed = false;
}
else {
this.isReversed = true;
}
},
reverse: function () {this.items.reverse()},
sortAlphaNum: function (a, b) {
if (a[this.sortKey] === undefined) return;
if (b[this.sortKey] === undefined) return;
var cva = a[this.sortKey].toString().toLowerCase();
var cvb = b[this.sortKey].toString().toLowerCase();
var reA = /[^a-zA-Z]/g;
var reN = /[^0-9]/g;
var aA = cva.replace(reA, "");
var bA = cvb.replace(reA, "");
if(aA === bA) {
var aN = parseInt(cva.replace(reN, ""), 10);
var bN = parseInt(cvb.replace(reN, ""), 10);
return aN === bN ? 0 : aN > bN ? 1 : -1;
}
return aA > bA ? 1 : -1;
},
setPage: function(pageNumber) {this.currentPage = pageNumber},
nextPage: function () {
if (this.pageNumber + 1 >= this.currentPage) return;
this.setPage(this.currentPage + 1);
},
previousPage: function () {
if (this.currentPage == 0) return;
this.setPage(this.currentPage - 1);
},
getVueItems: function(page){
this.$http.get(this.pageUrl)
.then((response) => {
var res = JSON.parse(response.data);
this.$set('items', res);
});
},
}
});
</script>
Regarding your first problem, You can break the bigger array in smaller arrays, than show those on paginated way and sort the smaller array, I have created a fiddle to demo it here.
Following is code to break it in smaller arrays:
computed: {
chunks () {
var size = 2, smallarray = [];
for (var i= 0; i<this.data.length; i+=size) {
smallarray.push(this.data.slice(i,i+size))
}
return smallarray
}
}
Regarding your second problem, if the issue is that items is not getting properly populated after this.$http.get call, it can be due to wrong scope of this variable as well, which can be corrected like following:
getVueItems: function(page){
var self = this
this.$http.get(this.pageUrl)
.then((response) => {
var res = JSON.parse(response.data);
self.items = res;
});
},

Resources