Limiting page numbers in serverside paging using angularjs and Bootstrap UI - angularjs-ng-repeat

I'm new to angular JS . I'm performing grid search and paging and sorting for the grid using angular js I have got an example in the below fiddle . But I'm not able to limit the pages for paging if the records are more in the example specified below.
HTML
<html xmlns:ng="http://angularjs.org" ng-app lang="en">
<head>
<meta charset="utf-8">
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/css/bootstrap.no-icons.min.css" rel="stylesheet">
<link href="http://netdna.bootstrapcdn.com/font-awesome/2.0/css/font-awesome.css" rel="stylesheet">
<script src="http://code.angularjs.org/1.1.0/angular.min.js"></script>
</head>
<body>
<script type="text/javascript">
var sortingOrder = 'name';
</script>
</div>
<div ng-controller="ctrlRead">
<div class="input-append">
<input type="text" ng-model="query" ng-change="search()" class="input-large search-query" placeholder="Search">
<span class="add-on"><i class="icon-search"></i></span>
</div>
<table class="table table-striped table-condensed table-hover">
<thead>
<tr>
<th class="id">Id <a ng-click="sort_by('id')"><i class="icon-sort"></i></a></th>
<th class="name">Name <a ng-click="sort_by('name')"><i class="icon-sort"></i></a></th>
<th class="description">Description <a ng-click="sort_by('description')"><i class="icon-sort"></i></a></th>
<th class="field3">Field 3 <a ng-click="sort_by('field3')"><i class="icon-sort"></i></a></th>
<th class="field4">Field 4 <a ng-click="sort_by('field4')"><i class="icon-sort"></i></a></th>
<th class="field5">Field 5 <a ng-click="sort_by('field5')"><i class="icon-sort"></i></a></th>
</tr>
</thead>
<tfoot>
<td colspan="6">
<div class="pagination pull-right">
<ul>
<li ng-class="{disabled: currentPage == 0}">
<a href ng-click="prevPage()">« Prev</a>
</li>
<li ng-repeat="n in range(pagedItems.length)"
ng-class="{active: n == currentPage}"
ng-click="setPage()">
<a href ng-bind="n + 1">1</a>
</li>
<li ng-class="{disabled: currentPage == pagedItems.length - 1}">
<a href ng-click="nextPage()">Next »</a>
</li>
</ul>
</div>
</td>
</tfoot>
<tbody>
<tr ng-repeat="item in pagedItems[currentPage] | orderBy:sortingOrder:reverse">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.description}}</td>
<td>{{item.field3}}</td>
<td>{{item.field4}}</td>
<td>{{item.field5}}</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
SCRIPT
function ctrlRead($scope, $filter) {
// init
$scope.sortingOrder = sortingOrder;
$scope.reverse = false;
$scope.filteredItems = [];
$scope.groupedItems = [];
$scope.itemsPerPage = 5;
$scope.pagedItems = [];
$scope.currentPage = 0;
$scope.items = [
{"id":"1","name":"name 1","description":"description 1","field3":"field3 1","field4":"field4 1","field5 ":"field5 1"},
{"id":"2","name":"name 2","description":"description 1","field3":"field3 2","field4":"field4 2","field5 ":"field5 2"},
{"id":"3","name":"name 3","description":"description 1","field3":"field3 3","field4":"field4 3","field5 ":"field5 3"},
{"id":"4","name":"name 4","description":"description 1","field3":"field3 4","field4":"field4 4","field5 ":"field5 4"},
{"id":"5","name":"name 5","description":"description 1","field3":"field3 5","field4":"field4 5","field5 ":"field5 5"},
{"id":"6","name":"name 6","description":"description 1","field3":"field3 6","field4":"field4 6","field5 ":"field5 6"},
{"id":"7","name":"name 7","description":"description 1","field3":"field3 7","field4":"field4 7","field5 ":"field5 7"},
{"id":"8","name":"name 8","description":"description 1","field3":"field3 8","field4":"field4 8","field5 ":"field5 8"},
{"id":"9","name":"name 9","description":"description 1","field3":"field3 9","field4":"field4 9","field5 ":"field5 9"},
{"id":"10","name":"name 10","description":"description 1","field3":"field3 10","field4":"field4 10","field5 ":"field5 10"},
{"id":"11","name":"name 11","description":"description 1","field3":"field3 11","field4":"field4 11","field5 ":"field5 11"},
{"id":"12","name":"name 12","description":"description 1","field3":"field3 12","field4":"field4 12","field5 ":"field5 12"},
{"id":"13","name":"name 13","description":"description 1","field3":"field3 13","field4":"field4 13","field5 ":"field5 13"},
{"id":"14","name":"name 14","description":"description 1","field3":"field3 14","field4":"field4 14","field5 ":"field5 14"},
{"id":"15","name":"name 15","description":"description 1","field3":"field3 15","field4":"field4 15","field5 ":"field5 15"},
{"id":"16","name":"name 16","description":"description 1","field3":"field3 16","field4":"field4 16","field5 ":"field5 16"},
{"id":"17","name":"name 17","description":"description 1","field3":"field3 17","field4":"field4 17","field5 ":"field5 17"},
{"id":"18","name":"name 18","description":"description 1","field3":"field3 18","field4":"field4 18","field5 ":"field5 18"},
{"id":"19","name":"name 19","description":"description 1","field3":"field3 19","field4":"field4 19","field5 ":"field5 19"},
{"id":"20","name":"name 20","description":"description 1","field3":"field3 20","field4":"field4 20","field5 ":"field5 20"}
];
var searchMatch = function (haystack, needle) {
if (!needle) {
return true;
}
return haystack.toLowerCase().indexOf(needle.toLowerCase()) !== -1;
};
// init the filtered items
$scope.search = function () {
$scope.filteredItems = $filter('filter')($scope.items, function (item) {
for(var attr in item) {
if (searchMatch(item[attr], $scope.query))
return true;
}
return false;
});
// take care of the sorting order
if ($scope.sortingOrder !== '') {
$scope.filteredItems = $filter('orderBy')($scope.filteredItems, $scope.sortingOrder, $scope.reverse);
}
$scope.currentPage = 0;
// now group by pages
$scope.groupToPages();
};
// calculate page in place
$scope.groupToPages = function () {
$scope.pagedItems = [];
for (var i = 0; i < $scope.filteredItems.length; i++) {
if (i % $scope.itemsPerPage === 0) {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)] = [ $scope.filteredItems[i] ];
} else {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)].push($scope.filteredItems[i]);
}
}
};
$scope.range = function (start, end) {
var ret = [];
if (!end) {
end = start;
start = 0;
}
for (var i = start; i < end; i++) {
ret.push(i);
}
return ret;
};
$scope.prevPage = function () {
if ($scope.currentPage > 0) {
$scope.currentPage--;
}
};
$scope.nextPage = function () {
if ($scope.currentPage < $scope.pagedItems.length - 1) {
$scope.currentPage++;
}
};
$scope.setPage = function () {
$scope.currentPage = this.n;
};
// functions have been describe process the data for display
$scope.search();
// change sorting order
$scope.sort_by = function(newSortingOrder) {
if ($scope.sortingOrder == newSortingOrder)
$scope.reverse = !$scope.reverse;
$scope.sortingOrder = newSortingOrder;
// icon setup
$('th i').each(function(){
// icon reset
$(this).removeClass().addClass('icon-sort');
});
if ($scope.reverse)
$('th.'+new_sorting_order+' i').removeClass().addClass('icon-chevron-up');
else
$('th.'+new_sorting_order+' i').removeClass().addClass('icon-chevron-down');
};
};
ctrlRead.$inject = ['$scope', '$filter'];
The output is given in the below link
Can anyone help me for limiting the page links in the above example .Thank you ..

I did some changes on your range function and now the pagination looks pretty good.
$scope.range = function (page, pages) {
var ret = [];
start = 0;
if (page+2 <= pages) {
end = page + 2;
}
else {
end = pages;
}
if (page-3 > 0) {
start = page -3;
}
for (var i = start; i < end; i++) {
if (i < end) {
ret.push(i);
}
}
return ret;
};
With this controls the pagination wold be show 2 items after the current and 3 before, please set the current page and the total page in the ng-repeat, with that changes you must see your number pagination properly.
<ul>
<li ng-class="{disabled: currentPage == 0}">
<a href ng-click="prevPage()">« Prev</a>
</li>
<li ng-repeat="n in range(currentPage, pagedItems.length)" ng-class="{active: n == currentPage}" ng-click="setPage()">
<a href ng-bind="n + 1">1</a>
</li>
<li ng-class="{disabled: currentPage == pagedItems.length - 1}">
<a href ng-click="nextPage()">Next »</a>
</li>
</ul>

The answer given by #Pirata21 works for me. .
If you have less number of pages then you can try changing the value
if(page-3>0)
{
start = page - 3;
}
In place of 3 you can write any number and check it(Kind of Trial and error).

Related

Filter records using daterangetime picker

I have a target where I need to filter the data using daterange with time picker. The thing is I need to show the result of my filtered data based on what I selected on the said daterange with time picker I have provided my codes below and my target. Thank you so much in advance.
Views:
<div class="card-body table-responsive py-3 px-3">
<input type="text" id="demo" name="daterange" value="06/05/2021 - 06/06/2021" style="width:350px;">
<button class="btn btn-success float-right" onclick="add_person()" data-dismiss="modal"><i class="glyphicon glyphicon-plus"></i> Add Person</button>
<table id="table_account" class="table table-bordered table-hover" cellspacing="0">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
<th>Email</th>
<th>Mobile</th>
<th>Role</th>
<th>Status </th>
<!-- <th>File </th> -->
<th>Added By</th>
<th>Date Created</th>
<th>Date Updated</th>
<th>Updated By</th>
<th style="width:100x;">Action</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</script>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
<th>Email</th>
<th>Mobile</th>
<th>Role</th>
<th>Status </th>
<th>Added By</th>
<th>Date Created</th>
<th>Date Updated</th>
<th>Updated By</th>
<th style="width:100x;">Action</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
Ajax:
<script>
// first, put this at the top of your JS code.
let dateParams = {}
// update this with setting dataParams
$('#demo').daterangepicker({
"timePicker": true,
"timePicker24Hour": true,
"startDate": "06/05/2021",
"endDate": "06/06/2021",
locale: {
format: 'M/DD/YYYY hh:mm A'
}
}, function(start, end, label) {
// set the dateParam obj
dateParams = {
start: start.format('YYYY-MM-DD hh:mm'),
end: end.format('YYYY-MM-DD hh:mm')
}
console.log('New date range selected: ' + start.format('YYYY-MM-DD hh:mm') + ' to ' + end.format('YYYY-MM-DD hh:mm') + ' (predefined range: ' + start + + end +')');
});
$(document).ready(function() {
//datatables
table = $('#table_account').DataTable({
dom: 'lBfrtip',
buttons: [
'print', 'csv', 'copy', 'excel', 'pdfHtml5'
],
"processing": false, //Feature control the processing indicator.
"serverSide": true, //Feature control DataTables' server-side processing mode.
"order": [], //Initial no order.
// Load data for the table's content from an Ajax source
"ajax": {
"url": "<?php echo site_url('profile/ajax_list')?>",
"type": "POST",
"data": function (dateParams) {
return $.extend( { "start": dateParams.start,
"end": dateParams.end,}, dateParams, {
});
},
},
//Set column definition initialization properties.
"columnDefs": [
{
"targets": [ 0 ], //first column
"orderable": false, //set not orderable
},
{
"targets": [ -1 ], //last column
"orderable": false, //set not orderable
},
],
});
});
setInterval( function () {
table.ajax.reload(null,false);
}, 1000);
</script>
Controller:
public function ajax_list()
{
$list = $this->profiles->get_datatables();
$data = array();
$no = $_POST['start'];
foreach ($list as $person) {
$no++;
$row = array();
$row[] = $person->firstname;
$row[] = $person->lastname;
$row[] = $person->username;
$row[] = $person->email;
$row[] = $person->mobile;
$row[] = $person->role;
$row[] = $person->status;
$row[] = $person->addedBy;
$row[] = $person->dateCreated;
$row[] = $person->updatedBy;
$row[] = $person->dateUpdated;
//add html for action
$row[] = '<a class="btn btn-sm btn-primary" href="javascript:void(0)" title="Edit" onclick="edit_person('."'".$person->userID."'".')"><i class="glyphicon glyphicon-pencil"></i> Edit</a>';
$data[] = $row;
}
$output = array(
"draw" => $_POST['draw'],
"recordsTotal" => $this->profiles->count_all(),
"recordsFiltered" => $this->profiles->count_filtered(),
"data" => $data,
);
//output to json format
echo json_encode($output);
}
Model:
var $table = 'users';
var $column_order = array(null,'userID','firstname','lastname','username','email','mobile','addedBy','dateCreated');
var $order = array('userID' => 'desc');
var $column_search = array('email','firstname','lastname','username','email','mobile','dateCreated');
//set column field database for datatable orderable //set column field database for datatable searchable just firstname , lastname , address are searchable var $order = array('id' => 'desc'); // default order
private function _get_datatables_query()
{
if($this->input->post('daterange')){
$this->db->where('dateCreated >=', $this->input->post('start'));
$this->db->where('dateCreated <=', $this->input->post('end'));
}
// $this->input->post('start'); // YYYY-mm-dd
// $this->input->post('end'); // YYYY-mm-dd
$this->db->from($this->table);
$i = 0;
foreach ($this->column_search as $item) // loop column
{
if($_POST['search']['value']) // if datatable send POST for search
{
if($i===0) // first loop
{
$this->db->group_start(); // open bracket. query Where with OR clause better with bracket. because maybe can combine with other WHERE with AND.
$this->db->like($item, $_POST['search']['value']);
}
else
{
$this->db->or_like($item, $_POST['search']['value']);
}
if(count($this->column_search) - 1 == $i) //last loop
$this->db->group_end(); //close bracket
}
$i++;
}
if(isset($_POST['order'])) // here order processing
{
$this->db->order_by($this->column_order[$_POST['order']['0']['column']], $_POST['order']['0']['dir']);
}
else if(isset($this->order))
{
$order = $this->order;
$this->db->order_by(key($order), $order[key($order)]);
}
}
function get_datatables()
{
$this->_get_datatables_query();
if($_POST['length'] != -1)
$this->db->limit($_POST['length'], $_POST['start']);
$query = $this->db->get();
return $query->result();
}
To connect the calendar with the data output table, edit your daterangepicker initialization:
// first, put this at the top of your JS code.
let dateParams = {}
// update this with setting dataParams
$('#demo').daterangepicker({
"timePicker": true,
"timePicker24Hour": true,
"startDate": "06/05/2021",
"endDate": "06/06/2021",
locale: {
format: 'M/DD hh:mm A'
}
}, function(start, end, label) {
// set the dateParam obj
dataParams = {
start: start.format('YYYY-MM-DD'),
end: end.format('YYYY-MM-DD')
}
// reload the table
table.ajax.reload();
//console.log('New date range selected: ' + start.format('YYYY-MM-DD') + ' to ' + end.format('YYYY-MM-DD') + ' (predefined range: ' + label + ')');
});
Over in your DataTable() setup change your ajax to pass the start and end dates
"ajax": {
"url": "<?php echo site_url('profile/ajax_list')?>",
"type": "POST",
"data": function ( d ) {
// add this
return $.extend( {}, d, {
"start": dataParams.start,
"end": dataParams.end
});
// could also be written: return $.extend( {}, d, dataParams);
}
}
Finally, you'll need to pick this up in your CI app so you can search you DB.
$this->input->post('start'); // YYYY-mm-dd
$this->input->post('end'); // YYYY-mm-dd
Then this is just a nit. Please move <table id="table_account" class="table table-bordered table-hover" cellspacing="0"> to right above the first <thead>. Right now there is the datepicker element in between them. Might not matter, but it should be fixed.
https://datatables.net/reference/option/ajax

First column of my DataTable has same width that all DataTable header

I set the headers of my DataTable dynamically
for (i = 0; i < nvs; i++) {
var id = i + 1;
$("#headersgrid").append(
'<th id="header' + id + '">header</th>'
);
parametros[i] = $("#vsdata" + id).text();
$("#header" + id).text(parametros[i]);
}
After that I have this code for my Ajax request:
$("#spresultado-datatable").DataTable({
responsive: true,
destroy: true,
"processing": true,
"serverSide": false,
"filter": true,
"ordering": true,
//"autoWidth": false,
"language": {
"processing": "Procesando...",
"lengthMenu": "Mostrar _MENU_ registros por pagina",
"zeroRecords": "No se encontraron resultados",
"info": "Mostrando pagina _PAGE_ de _PAGES_",
"infoEmpty": "Mostrando registros del 0 al 0 de un total de 0 registros",
"infoFiltered": "(filtrado de un total de _MAX_ registros)",
"paginate": {
"first": "Primero",
"last": "Último",
"next": "Siguiente",
"previous": "Anterior"
}
},
"ajax": {
"url": "/Spconsumer/Ejecutar",
"type": "POST",
"data": DTO,
"datatype": "json",
"dataSrc": function (response) {
var i = 0;
var j = 0;
for (j = 0; j < response.data.length; j++) {
columns = [];
$.each(response.data[j].parametro, function (key, value) {
var my_item = {};
var id = i + 1;
my_item.data = value;
my_item.name = parametros[i];
//my_item.autoWidth = true;
columns.push(value);
i++;
});
data.push(columns);
}
return data;
},
"columnDefs": [
{ "autoWidth": true , "targets": 0 }
]
}
});
I get the data correctly and pass it to my Index.cshtml in order to show the table:
<div class="users-list-table" id="gridresultadosp">
<div class="card">
<div class="card-header row">
<div class="col-12 col-sm-6 col-lg-8">
<h1 class="card-title">Spconsumer - Resultado Ejecucion SP</h1>
</div>
</div>
<div class="card-content">
<div class="card-body">
<!-- datatable start -->
<div class="table-responsive">
<table id="spresultado-datatable" class="table mb-0">
<thead>
<tr id="headersgrid">
</tr>
</thead>
</table>
</div>
<!-- datatable ends -->
</div>
</div>
</div>
</div>
I am getting the data correctly in my Html but I have a problem with the first column:
As you can see in the image the data loads correctly, ordering and filtering work ok but the width of the first column spans the full width of the entire header of the data table. I tried everything, search the internet without success, please if someone can guide me on how to solve it
I managed to resolve the problem:
I changed:
for (i = 0; i < nvs; i++) {
var id = i + 1;
$("#headersgrid").append(
'<th id="header' + id + '">header</th>'
);
parametros[i] = $("#vsdata" + id).text();
$("#header" + id).text(parametros[i]);
}
To
for (i = 0; i < nvs; i++) {
var id = i + 1;
parametros[i] = $("#vsdata" + id).text();
$("#headersgrid").append(
'<th>' + parametros[i] + '</th>'
);
}
Using <th id="header' + id + '">header</th> was the origin of the problem

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;
});
},

Vue.js sorting is not working when fetching from 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.

Javascript buttons using arrays

My assignment is to create 4 buttons that scroll through 20 pictures. The pictures are currently labeled usa1.jpg all the way up to usa20.jpg. The goal is to create a first/last button that takes you all the way to the very first and last picture, and a classic next and previous button to go through the pictures. My instructor is old fashioned and this is the very first javascript class so if you see any really old looking code please remember that the instructor is requiring me to use it as it is shown and not to use anything that is beyond beginner level; otherwise I will get docked points for this assignment. Right now the images are not loading on the site when I pull it up. Any other tips or info would also be greatly appreciated.
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="styles/usa.css">
<title>USA Tour</title>
</head>
<body>
<table>
<thead>
<tr>
<th>Images From USA Tour 2007</th>
</tr>
</thead>
<tfoot>
<tr>
<td id="btns">
<button type="button" id="first"><=</button>
<button type="button" id="previous"><</button>
<button type="button" id="next">></button>
<button type="button" id="last">=></button>
</td>
</tr>
</tfoot>
<tbody>
<tr>
<td id="usaimg"></td>
</tr>
</tbody>
</table>
<script type="text/javascript" src="scripts/usa.js"></script>
</body>
</html>
-----------------------------------------------------------------------
window.onload = function() {
var loadFirstBtn = document.getElementById("first");
var loadNextBtn = document.getElementById("next");
var loadPrevBtn = document.getElementById("previous");
var loadLastBtn = document.getElementById("last");
var extension = ".jpg";
var imgPath = "images/usa-";
var images = [];
function loadImages() {
for (var i = 0; i < 20; i++) {
images[i] = new Image();
if () {
images[i].src = imgPath + (i + 1) + extension;
}
console.log(images[i].src);
}
}
loadFirstBtn.onclick = function(){
var tds = document.getElementsById("btns");
var len = images.length;
for (var i = 0) {
tds[i].appendChild(images[i]);
}
}
loadNextBtn.onclick = function(){
var tds = document.getElementsById("btns");
var len = images.length;
for (var i = 0; i++) {
tds[i].appendChild(images[i]);
images.sort(function(a, b) {
return a - b;
});
}
}
loadPrevBtn.onclick = function(){
var tds = document.getElementsById("btns");
var len = images.length;
for (var i = 0; i--) {
tds[i].appendChild(images[i]);
images.sort(function(a, b) {
return b - a;
});
}
}
loadLastBtn.onclick = function(){
var tds = document.getElementsById("btns");
var len = images.length;
for (var i = 20) {
tds[i].appendChild(images[i]);
}
}
loadImages();
}

Resources