UI Grid get sorted items with pagination - angularjs

I have checked all stackoverflow posts related to ui-grid sorted rows without any success so I am opening one more question.
SHORT : Need a way to get sorted rows following current sorting criteria.
My problem is that I have an instance of UI Grid with pagination and I can not get the sorted data after it was added using a $mdDialog modal. It is shown at the right position in the tabel, but behind, in all objects it is stored the new element is on the last position.
I call the ui-grid instance using a service to keep all stuff in one place:
// Default service for init a ui-grid instance
app.serivce('testService', function(){
var defaultGridOptions = {
enableColumnMenus: false,
enablePaginationControls: true,
paginationPageSizes: [5],
multipleSorting: false,
treeRowHeaderAlwaysVisible: false,
paginationPageSize: 5,
enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER
};
// Each columns sort rule
// Position 0 from columnsOrder sorts position 0 from columnDefs and so on
var defaultColSort = [{
sort: { direction: uiGridConstants.ASC, priority: 0 }
}];
this.createGridOptions = function (gridData, columnDefs, gridOpts) {
gridOpts = typeof gridOpts !== 'undefined' ? gridOpts : {};
var gridOptions = angular.extend({}, defaultGridOptions, gridOpts);
for(var i = 0; i < defaultColSort.length; i++)
columnDefs[i] = angular.extend({}, defaultColSort[i], columnDefs[i]);
gridOptions.data = gridData;
gridOptions.columnDefs = columnDefs;
return gridOptions;
};
// The metod that should move to the desired page
this.jumpToGridItem = function(api, entry) {
var idx = -1;
var page = 0;
var sortedData = null;
// NEED A WAY TO GET SORTED DATA HERE
//idx = sortedData.indexOf(entry); -> checks the position of the new added item
if (idx == -1)
return false;
// Calculate the page where the element exists
page = Math.ceil(idx/api.grid.options.paginationPageSize);
// Jump to page
api.pagination.seek(page);
};
})
Here is my controller :
app.controller('testController', ['$scope', '$mdDialog', 'testService', function($scope, $mdDialog, testService){
var columnDefs = [
{
field: 'identifier',
name: 'Identifier'
}
];
var dummyData = [{ identifier: "Item" }, { identifier: 'Item 1' }, { identifier: "Item 2" }, { identifier: "Item 3" }];
var gridOptions = $scope.gridOptions = testService.createGridOptions(dummyData, columnDefs);
gridOptions.onRegisterApi = function (gridApi) {
$scope.gridApi = gridApi;
};
$scope.add = function () {
$mdDialog.show({
controller: function($mdDialog) {
var data = $scope.identifierVal;
$mdDialog.hide(data);
},
templateUrl: 'add.html',
parent: angular.element(document.body)
}).then(function (entry) {
// Data received when the modal is hidden
$scope.gridOptions.data.push(entry);
testService.jumpToGridItem($scope.gridApi, entry);
});
};
}]);
Right now I am appending the data with push(), this could be one reason, I think.
The method I have to update is jumpToGridItem, which actually should focus the page where the item was added.
Thank you
PS : Sorry for not posting a plnkr, I will do bit later if it is needed.

I finally found a way to achieve what I initially wanted. I ve found it a day after posting the question but I was busy enough to post the answer. The code below can be also found in a plnkr. It looks for a certain entry and goes to the page where it can be found.
I wanted this to focus a dynamically added entry in a ui-grid table from a dialog (modal form):
Controller :
var app = angular.module('stefanz', ['ui.grid', 'ui.grid.pagination']);
app.controller('MyCtrl', ['$scope', 'UIGridCustom', '$http', function($scope, UIGridCustom, $http){
// A part of data copied from ui-grid demos
var data = [{"name": "Ethel Price", "gender": "female", "company": "Enersol" },{"name": "Claudine Neal", "gender": "female", "company": "Sealoud" },{"name": "Beryl Rice", "gender": "female", "company": "Velity" },{"name": "Wilder Gonzales", "gender": "male", "company": "Geekko" },{"name": "Georgina Schultz", "gender": "female", "company": "Suretech" },{"name": "Carroll Buchanan", "gender": "male", "company": "Ecosys" },{"name": "Valarie Atkinson", "gender": "female", "company": "Hopeli" },{"name": "Schroeder Mathews", "gender": "male", "company": "Polarium" },{"name": "Lynda Mendoza", "gender": "female", "company": "Dogspa" },{"name": "Sarah Massey", "gender": "female", "company": "Bisba" },{"name": "Robles Boyle", "gender": "male", "company": "Comtract" },{"name": "Evans Hickman", "gender": "male", "company": "Parleynet" },{"name": "Dawson Barber", "gender": "male", "company": "Dymi" }];
var colDefs = [{
label: "name",
name: "name"
}, {
label: "gender",
name: "gender"
}, {
label: "company",
name: "company"
}];
// Call the service for init
var gridOptions = $scope.gridOptions = UIGridCustom.createGridOptions(data, colDefs);
gridOptions.onRegisterApi = function(api) {
$scope.gridApi = api;
}
$scope.getItemPage = function(name) {
UIGridCustom.jumpToGridItem($scope.gridApi, name);
}
}]);
app.service('UIGridCustom', ['uiGridConstants', 'utils', function(uiGridConstants, utils){
var defaultGridOptions = {
enableColumnMenus: false,
enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
enablePaginationControls: false,
paginationPageSize: 5,
multipleSorting: true
};
// Each columns sort rule
// Position 0 from columnsOrder sorts position 0 from columnDefs and so on
// Could be overwritten into columnDefs
// Docs : http://ui-grid.info/docs/#/api/ui.grid.class:GridOptions
var defaultColSort = [];
//1st column default sorting
defaultColSort[{
sort: { direction: uiGridConstants.ASC, priority: 0 }
}];
// For sorting 2nd column
// defaultColSort[1] = {
// sort: { direction: uiGridConstants.ASC, priority: 0 }
// };
this.createGridOptions = function (gridData, columnDefs, stefanzGridOpts) {
// Overwrite defaults with custom passed options for grid
var stefanzGridOpts = typeof stefanzGridOpts !== 'undefined' ? stefanzGridOpts : {};
var gridOptions = angular.extend({}, defaultGridOptions, stefanzGridOpts);
// Force sorting following the default/custom column sort
for(var i = 0; i < defaultColSort.length; i++)
columnDefs[i] = angular.extend({}, defaultColSort[i], columnDefs[i]);
// Grid init
gridOptions.data = gridData;
gridOptions.columnDefs = columnDefs;
return gridOptions;
};
this.jumpToGridItem = function(api, name) {
var idx = 0;
var page = 0;
var sorting = prepareCriteria(api.grid.getColumnSorting());
var data = dataObjectSort(prepareRows(api.grid.rows), sorting);
entry = getEntryByName(data, name);
idx = data.indexOf(entry) + 1;
if (!idx)
return false;
// Calculate the page where the element exists
page = Math.ceil(idx/api.grid.options.paginationPageSize);
alert(name + 'is found on page ' + page);
// Jump to page
api.pagination.seek(page);
};
// Takes the row's entity and put in a new array as a top-level item
// Userful for further data handling
var prepareRows = function(rows) {
if (rows.length == 0)
return false;
var preparedRows = [];
rows.forEach(function(row){
// Do not need to handle the rows that are not in current filter (hidden)
if (row.visible == false)
return true;
preparedRows.push(row.entity);
});
return preparedRows;
};
// We are comparing whole enter and as a parameter we are sending a name
var getEntryByName = function(data, searchedName) {
for(var i = 0; i < data.length; i++) {
if (data[i]['name'] == searchedName)
return data[i];
}
return false;
}
var dataObjectSort = function(data, criteria) {
return data.sort(utils.dynamicSortMultiple(criteria));
};
var prepareCriteria = function(colSorting) {
var sorting = [];
var fields = [];
// Take just needed fields
colSorting.forEach(function(column){
sorting.push({
field: column.field,
direction: column.sort.direction,
priority: column.sort.priority
})
});
// Sort criterias by priority - UI grid works like this
// Reason : http://ui-grid.info/docs/#/api/ui.grid.class:GridOptions.columnDef#properties_sort
sorting.sort(function(a, b){
if (a.priority < b.priority) return -1;
else if (a.priority > b.priority) return 1;
else return 0;
});
// Prepare fields for sorting
sorting.forEach(function(sort){
// Dymanic sort (above) needs "-" sign for descendent direction
if (sort.direction != uiGridConstants.ASC)
sort.field = '-' + sort.field;
fields.push(sort.field);
});
return fields;
};
}]);
// Keep utils methods into a separate service
// Here all sorting methods will appear
app.service('utils', function(){
function getJsonValue(obj, path) {
if (!path || path == '')
return obj;
path = path.split('.');
var len = path.length;
for (var i = 0; i < len - 1; i++) {
var prop = path[i].split(/\[([^\]]+)]/); // indication[4] => [indication, 4]; indication => [indication]
if (prop.length == 1) {
obj = obj[prop[0]];
} else {
obj = obj[prop[0]][prop[1]];
}
}
var prop = path[len - 1].split(/\[([^\]]+)]/); // indication[4] => [indication, 4]; indication => [indication]
if (prop.length == 1) {
return obj[prop[0]];
} else {
if (prop.length == 2) {
return obj[prop[0]][prop[1]];
} else {
if(prop.length ==3) {
return obj[prop[0]][prop[1]]; // this is a hack!
} else {
return obj[prop[0]][prop[1]][prop[3]]; // this is a hack!
}
}
}
};
//http://stackoverflow.com/questions/1129216/sort-array-of-objects-by-string-property-value-in-javascript/4760279#4760279
function dynamicSort(property) {
var sortOrder = 1;
if(property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a,b) {
var aInsensitive = getJsonValue(a, property).toLowerCase();
var bInsensitive = getJsonValue(b, property).toLowerCase();
var result = (aInsensitive < bInsensitive) ? -1 : (aInsensitive > bInsensitive) ? 1 : 0;
return result * sortOrder;
}
};
function dynamicSortMultiple(props) {
return function (obj1, obj2) {
var i = 0, result = 0, numberOfProperties = props.length;
while(result === 0 && i < numberOfProperties) {
result = dynamicSort(props[i])(obj1, obj2);
i++;
}
return result;
}
};
return {
getJsonValue: function(obj, path) {
return getJsonValue(obj, path);
},
dynamicSort: function(property) {
return dynamicSort(property);
},
dynamicSortMultiple: function(props) {
return dynamicSortMultiple(props);
}
}
});
HTML
<!DOCTYPE html>
<html ng-app="stefanz">
<head>
<script data-require="angularjs_1_3_15#*" data-semver="1.3.15" src="https://code.angularjs.org/1.3.15/angular.min.js"></script>
<script data-require="angularjs_1_3_15#*" data-semver="1.3.15" src="https://code.angularjs.org/1.3.15/angular-animate.min.js"></script>
<script data-require="angularjs_1_3_15#*" data-semver="1.3.15" src="https://code.angularjs.org/1.3.15/angular-aria.min.js"></script>
<script data-require="jquery#*" data-semver="2.1.4" src="https://code.jquery.com/jquery-2.1.4.js"></script>
<link data-require="ui-grid#*" data-semver="3.0.7" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/3.0.7/ui-grid.css" />
<script data-require="ui-grid#*" data-semver="3.0.7" src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/3.0.7/ui-grid.js"></script>
<script data-require="bootstrap#~3.3.5" data-semver="3.3.6" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="MyCtrl">
<div ui-grid="gridOptions" ui-grid-pagination class="grid"></div>
<div class="centerAlignedText">
<ul>
<li><a ng-click="getItemPage('Ethel Price')">Get Ethel Price</a></li>
<li><a ng-click="getItemPage('Schroeder Mathews')">Get Schroeder Mathews</a></li>
<li><a ng-click="getItemPage('Dawson Barber')">Get Dawson Barber</a></li>
<li><a ng-click="getItemPage('Sarah Massey')">Get Sarah Massey</a></li>
</ul>
</div>
<div class="centerAlignedText" ng-if="gridOptions.totalItems > 0">
<div class="paginationButtonsIcon boldText" style="width: 100px; display: inline-block;">
<md-button ng-if="gridApi.pagination.getPage() > 1" class="paginationButtons" ng-click="gridApi.pagination.previousPage()" style="width: 90px;">
<span class="notTransformedText boldText">Previous</span>
</md-button>
</div>
<div ng-repeat="n in gridApi.pagination.getTotalPages()" style="display: inline-block;">
<md-button ng-if="(gridApi.pagination.getTotalPages() < 11)
|| (gridApi.pagination.getPage() < 7 && n < 10)
|| (n > gridApi.pagination.getPage() - 7 && n < gridApi.pagination.getPage() + 4)
|| (gridApi.pagination.getPage() > gridApi.pagination.getTotalPages() - 5 && n > gridApi.pagination.getTotalPages() - 11)" class="paginationButtons md-mini md-icon-button md-primary" ng-click="gridApi.pagination.seek($index + 1)">
<span class="paginationButtonsIcon boldText" ng-if="gridApi.pagination.getPage() === $index + 1">
{{$index + 1}}
</span>
<span class="paginationButtonsIcon" ng-if="gridApi.pagination.getPage() !== $index + 1">
{{$index + 1}}
</span>
</md-button>
</div>
<div class="paginationButtonsIcon boldText" style="width: 100px; display: inline-block;">
<md-button ng-if="gridApi.pagination.getPage() < gridApi.pagination.getTotalPages()" class="paginationButtons md-icon-button md-primary" ng-click="gridApi.pagination.nextPage()" style="width: 90px;">
<span class="notTransformedText boldText">Next</span>
</md-button>
</div>
</div>
</body>
</html>

Related

How to change the pagination after filtering, and not looking for the result on the pages?

The pagination would not update itself as the filter applied. Data is loaded from the database using a Python script. I'm new to AngularJS. How do I change the code to solve this problem?
I tried to solve the problem by the link: Filter through pagination angular
Failed to deal :(
Corrected code ↓
<!-- language: lang-json -->
// **Listing index.json**
[{
"name": "265/70R16 112T Ice Zero",
"width": "265",
"height": "70",
"razmer": "R16",
"price": 112,
"model":"Ice Zero",
"brand":"Pirelli"
},
{
"name": "225/55R17 112T Ice Maiz",
"width": "225",
"height": "55",
"razmer": "R17",
"price": 102,
"model":"Ice Maiz",
"brand":"Continental"
},
{
"name": "205/50R16 112T PSX",
"width": "205",
"height": "50",
"razmer": "R16",
"price": 92,
"model":"PSX",
"brand":"Bridgstoun"
},
{
"name": "205/55R17 112T Brrr",
"width": "205",
"height": "55",
"razmer": "R17",
"price": 100,
"model":"Brrr",
"brand":"Toyo"
},
{
"name": "225/55R17 112T ICE WinterSport",
"width": "225",
"height": "55",
"razmer": "R17",
"price": 102,
"model":"ICE WinterSport",
"brand":"Dunlop"
},
{
"name": "255/65R18 112T Winter",
"width": "255",
"height": "65",
"razmer": "R18",
"price": 122,
"model":"Winter",
"brand":"Nokian"
},
{
"name": "225/55R17 112T Hmit 5",
"width": "225",
"height": "55",
"razmer": "R17",
"price": 102,
"model":"Hmit 5",
"brand":"Kunho"
},
{
"name": "245/45R20 112T Ice Sport",
"width": "245",
"height": "45",
"razmer": "R20",
"price": 202,
"model":"Ice Sport",
"brand":"GoodYear"
}]
// **Listing index.js**
var app = angular.module('app', [])
.factory('pagination', function ($sce) {
var currentPage = 1;
var itemsPerPage = 3;
var pageMax = 12;
var pageTo = 0;
var pageFrom = 0;
var products = [];
var click_count_next = 0;
return {
setProducts: function (newProducts) {
products = newProducts
}, /* END of setProducts */
getPageProducts: function (num) {
var num = angular.isUndefined(num) ? 0 : num;
var first = itemsPerPage * num;
var last = first + itemsPerPage;
currentPage = num;
last = last > products.length ? (products.length) : last;
return products.slice(first, last);
}, /* END of getPageProducts */
getTotalPagesNum: function () {
return Math.ceil(products.length / itemsPerPage);
}, /* END of getTotalPagesNum */
getPaginationList: function (pcn) {
var pcn = angular.isUndefined(pcn) ? 0 : pcn;
var pagesNum = this.getTotalPagesNum();
var paginationList = [];
/*document.write(pagesNum);*/
paginationList.push({
name: $sce.trustAsHtml('«'),
link: 'prev'
});
if (pageMax < pagesNum) {
if (pcn > Math.ceil(pageMax / 2) + pageFrom) {
pageFrom++;
pageTo = pageMax + pageFrom;
if (pageTo > pagesNum) {
pageTo = pagesNum;
pageFrom = pagesNum - pageMax;
}
}
if (pcn < Math.ceil(pageMax / 2) + pageFrom) {
pageTo--;
pageFrom = pageTo - pageMax;
if (pageFrom < 0) {
pageFrom = 0;
pageTo = pageMax;
}
}
if (pageTo <= pagesNum) {
for (var i = pageFrom; i < pageTo; i++) {
var name = i + 1;
paginationList.push({
name: $sce.trustAsHtml(String(name)),
link: i
});
};
}
}
else {
for (var i = 0; i < pagesNum; i++) {
var name = i + 1;
paginationList.push({
name: $sce.trustAsHtml(String(name)),
link: i
});
};
}
paginationList.push({
name: $sce.trustAsHtml('»'),
link: 'next'
});
if (pagesNum > 1) {
return paginationList;
} else {
return null;
}
}, /* END of getPaginationList */
getUpdatePagination: function () {
return this.getPaginationList(click_count_next)
},
getPrevPageProducts: function () {
var prevPageNum = currentPage - 1;
if (prevPageNum < 0) prevPageNum = 0;
this.getPageProducts(prevPageNum);
return currentPage;
}, /* END of getPrevPageProducts */
getNextPageProducts: function () {
var nextPageNum = currentPage + 1;
var pagesNum = this.getTotalPagesNum();
if (nextPageNum >= pagesNum) nextPageNum = pagesNum - 1;
this.getPageProducts(nextPageNum);
return currentPage;
}, /* END of getNextPageProducts */
getCurrentPageNum: function () {
return currentPage;
}, /* END of getCurrentPageNum */
}
}) /* END of factory-pagination */
///// CONTROLLER START
.controller('mainCtrl', function ($scope, $http, $filter, pagination) {
$http.get('https://mesnalex.com/stackoverflow/index.json')
.success(function(data){
$scope.products = $scope.ProductObj = data;
$scope.filterProducts = function () {
var chain = new filterChain($scope.ProductObj);
$scope.products = chain
.applyFilter('filter', [{ brand: $scope.brand }])
.applyFilter('filter', [{ razmer: $scope.razmer }])
.applyFilter('filter', [{ width: $scope.width }])
.applyFilter('filter', [{ height: $scope.height }])
.value;
pagination.setProducts($scope.products);
$scope.products = pagination.getPageProducts($scope.currentPage);
$scope.paginationList = pagination.getPaginationList($scope.page_click_next);
};
pagination.setProducts($scope.products);
$scope.products = pagination.getPageProducts($scope.currentPage);
$scope.paginationList = pagination.getPaginationList($scope.page_click_next);
$scope.showPage = function (page) {
if (page == 'prev') {
$scope.products = pagination.getPageProducts(page = pagination.getPrevPageProducts());
$scope.paginationList = pagination.getPaginationList(page);
}
else if (page == 'next') {
$scope.products = pagination.getPageProducts(page = pagination.getNextPageProducts());
$scope.paginationList = pagination.getPaginationList(page);
} else {
$scope.products = pagination.getPageProducts(page);
$scope.paginationList = pagination.getPaginationList(page);
}
}
$scope.currentPageNum = function () {
return pagination.getCurrentPageNum();
}
function filterChain(value) {
this.value = value;
}
filterChain.prototype.applyFilter = function (filterName, args) {
args.unshift(this.value);
this.value = $filter(filterName).apply(undefined, args)
return this;
};
});
});
///// CONTROLLER END
app.filter('unique', function () {
return function (items, filterOn) {
if (filterOn === false) {
return items;
}
if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
var hashCheck = {}, newItems = [];
var extractValueToCompare = function (item) {
if (angular.isObject(item) && angular.isString(filterOn)) {
return item[filterOn];
} else {
return item;
}
};
angular.forEach(items, function (item) {
var valueToCheck, isDuplicate = false;
for (var i = 0; i < newItems.length; i++) {
if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
newItems.push(item);
}
});
items = newItems;
}
return items;
};
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.23/angular.min.js"></script>
<!-- **Listing index.html** -->
<!-- some code -->
<body ng-app="app" ng-controller="mainCtrl">
<!--<div class="my_blog"><h2>My Blog</h2> -->
<!-- FILTER BOX START -->
<select ng-model="brand" ng-change="filterProducts()" style="margin-top:35px;width:210px;" autocomplete="off">
<option style="color:gray;" value="{{undefined}}">All</option>
<option ng-repeat="item in ProductObj | unique: 'brand' | orderBy: 'brand'" id="brand_Select" >{{ item.brand }}</option>
</select>
<select ng-model="height" ng-change="filterProducts()" style="float:left;margin-top:35px;width:210px;" autocomplete="off">
<option style="color:gray;" value="{{undefined}}">All</option>
<option ng-repeat="item in ProductObj | unique: 'height' | orderBy: 'height'" id="height_Select" >{{ item.height }}</option>
</select>
<!-- FILTER BOX END -->
<!-- LISTING PRODUCTS START -->
<div ng-repeat="item in products">
<div>
<h5>{{ item.brand }} {{ item.model }}</h5>
<h5>{{ item.name }}</h5>
<h5>{{ item.price }}</h5>
</div>
</div>
<!-- LISTING PRODUCTS END -->
<!-- PAGINATION START -->
<ul class="pagination">
<li class="page-item" ng-repeat="page in paginationList" ng-click="showPage(page.link)" ng-class="{'active': currentPageNum() == page.link}"><a class="page-link" ng-bind-html="page.name"></a></li>
</ul>
<!-- PAGINATION END -->
</body>
<!-- some code -->
Problem solved! :)
Changes that I made to the controller(for 4 filters):
.controller('mainCtrl', function ($scope, $http, $filter, pagination) {
$http.get('./out_data.php?action=getPosts')
.success(function(data){
$scope.products = $scope.ProductObj = data;
$scope.filterProducts = function () {
var chain = new filterChain($scope.ProductObj);
$scope.products = chain
.applyFilter('filter', [{ brand: $scope.brand }])
.applyFilter('filter', [{ razmer: $scope.razmer }])
.applyFilter('filter', [{ width: $scope.width }])
.applyFilter('filter', [{ height: $scope.height }])
.value;
pagination.setProducts($scope.products);
$scope.products = pagination.getPageProducts($scope.currentPage);
$scope.paginationList = pagination.getPaginationList($scope.page_click_next);
};
pagination.setProducts($scope.products);
$scope.products = pagination.getPageProducts($scope.currentPage);
$scope.paginationList = pagination.getPaginationList($scope.page_click_next);
function filterChain(value) {
this.value = value;
}
filterChain.prototype.applyFilter = function (filterName, args) {
args.unshift(this.value);
this.value = $filter(filterName).apply(undefined, args)
return this;
};
});
The changes I made to the getPaginationList function:
getPaginationList: function (pcn) {
var pcn = angular.isUndefined(pcn) ? 0 : pcn;
var pagesNum = this.getTotalPagesNum();
var paginationList = [];
/*document.write(pagesNum);*/
paginationList.push({
name: $sce.trustAsHtml('«'),
link: 'prev'
});
if (pageMax < pagesNum) {
if (pcn > Math.ceil(pageMax / 2) + pageFrom) {
pageFrom++;
pageTo = pageMax + pageFrom;
if (pageTo > pagesNum) {
pageTo = pagesNum;
pageFrom = pagesNum - pageMax;
}
}
if (pcn < Math.ceil(pageMax / 2) + pageFrom) {
pageTo--;
pageFrom = pageTo - pageMax;
if (pageFrom < 0) {
pageFrom = 0;
pageTo = pageMax;
}
}
if (pageTo <= pagesNum) {
for (var i = pageFrom; i < pageTo; i++) {
var name = i + 1;
paginationList.push({
name: $sce.trustAsHtml(String(name)),
link: i
});
};
}
}
else {
for (var i = 0; i < pagesNum; i++) {
var name = i + 1;
paginationList.push({
name: $sce.trustAsHtml(String(name)),
link: i
});
};
}
paginationList.push({
name: $sce.trustAsHtml('»'),
link: 'next'
});
if (pagesNum > 1) {
return paginationList;
} else {
return null;
}
}, /* END of getPaginationList */
Corrections to index.html:
<select ng-model="brand" ng-change="filterProducts()" style="margin-top:15px;width:210px;" autocomplete="off">
<option style="color:gray;" value="{{undefined}}">All</option>
<option ng-repeat="item in ProductObj | unique: 'brand' | orderBy: 'brand'" id="brand_Select" >{{ item.brand }}</option>
</select>
....
<div ng-repeat="item in products">
<div class="thumbnail">
<h5>{{ item.brand }} {{ item.model }}</h5>
<h5>{{ item.full_name }}</h5>
<h5>{{ item.roz_price }}</h5>
</div>
</div>

How to split my JSON object in angularJS

I am trying to create pagination for my table that lists the objects returned from my DB as an object. My data structure will look something like:
$scope.myJSONObj = {
app1: {
id: 1,
appName: "appIntegrated1",
status: "Pending"
},
app2: {
id: 2,
appName: "appIntegrated2",
status: "Pending"
},
app3: {
id: 3,
appName: "appIntegrated3",
status: "Completed"
},
app4: {
id: 4,
appName: "appIntegrated4",
status: "Pending"
},
app5: {
id: 5,
appName: "appIntegrated5",
status: "Pending"
},
app6: {
id: 6,
appName: "appIntegrated6",
status: "Pending"
},
app7: {
id: 7,
appName: "appIntegrated7",
status: "Pending"
},
app8: {
id: 8,
appName: "appIntegrated8",
status: "Pending"
},
app9: {
id: 9,
appName: "appIntegrated9",
status: "Pending"
},
app10: {
id: 10,
appName: "appIntegrated10",
status: "Pending"
}
I am trying to split my structure in half, and display the first five results. I have a prev/next button, and when I click next, it should display the next 5 results (in this case the last 5). However, for everything to work, I need to be able to split my object, and so far every method I've researched involves arrays, and objects requiring some hack. I was wondering if I was missing something, or I have to create a solution to work with?
In pure JavaScript :
function getEntries(from, to) {
var entries = [];
for(var key in myJSONObj) {
// extract index after `app`
// var index = key.substring(3);
// Better way : extract index using regular expression, so it will match `something1`, `foo2`, `dummy3`
var index = parseInt(key.replace( /^\D+/g, ''));
if(index >= from && index <= to) {
entries.push(myJSONObj[key]);
}
}
return entries;
}
console.log(getEntries(0, 5));
Try _.chunk
https://lodash.com/docs/4.17.4#chunk
$scope.pages = _.chunk($scope.myJSONObj,5);
$scope.getPage = function( pageIndex ){
return $scope.pages[pageIndex];
}
It's untested - but I wrote a chunk method for you in vanilla JS since you can't use lodash.
function chunk(obj, chunkSize) {
var resultArray = [];
var resultArrayCurrentIndex = 0;
for (var key in obj) {
var item = obj[key];
if (resultArray[resultArrayCurrentIndex].length <= chunkSize) {
if (!resultArray[resultArrayCurrentIndex]) {
resultArray[resultArrayCurrentIndex] = [item];
} else {
resultArray[resultArrayCurrentIndex].push(item)
}
} else {
resultArrayCurrentIndex++
resultArray[resultArrayCurrentIndex] = [item];
}
}
return resultArray;
}
Then you can access it like this:
$scope.pages = chunk(yourObject, 5);
$scope.getPage = function(index){
return $scope.pages[index];
}
EDIT - changed it to accept an obj.
Used Object.keys, Array.prototype.slice and Array.prototype.reduce to solve your issue. Hope this helps
angular.module('app',[])
.controller('TestCtrl', function($scope){
$scope.myJSONObj = {"app1":{"id":1,"appName":"appIntegrated1","status":"Pending"},"app2":{"id":2,"appName":"appIntegrated2","status":"Pending"},"app3":{"id":3,"appName":"appIntegrated3","status":"Completed"},"app4":{"id":4,"appName":"appIntegrated4","status":"Pending"},"app5":{"id":5,"appName":"appIntegrated5","status":"Pending"},"app6":{"id":6,"appName":"appIntegrated6","status":"Pending"},"app7":{"id":7,"appName":"appIntegrated7","status":"Pending"},"app8":{"id":8,"appName":"appIntegrated8","status":"Pending"},"app9":{"id":9,"appName":"appIntegrated9","status":"Pending"},"app10":{"id":10,"appName":"appIntegrated10","status":"Pending"}};
$scope.currentPage = 0;
$scope.pageSize = 5;
$scope.totalPage = Math.ceil( Object.keys($scope.myJSONObj).length/$scope.pageSize);
//pageNumber starts from 0 here
$scope.goToPage = function(pageNumber) {
pageNumber = pageNumber>=0?pageNumber:0;
var from = pageNumber*$scope.pageSize;
var to = from + $scope.pageSize;
return Object.keys($scope.myJSONObj).slice(from,to).reduce(function(a,b){
a[b] = $scope.myJSONObj[b];
return a;
},{});
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="TestCtrl">
<button ng-disabled="currentPage===0" ng-click="currentPage = currentPage - 1">prev</button>
<button ng-disabled="currentPage===totalPage-1" ng-click="currentPage = currentPage + 1">next</button>
<b>Page: {{currentPage+1}}/{{totalPage}}</b>
<pre>{{goToPage(currentPage) | json}}</pre>
</div>

Angular Custom filters: match value with value in array and get corresponding name

Blockquote
I want to convert a number to a animal with a Angular filter.
I have the following ng-repeat:
<div ng-repeat="speed in speeds track by $index">
You're faster than a <span ng-bind="speed.value | speedToAnimal"></span>
</div>
speed.value wil give you a value like 42.9
Ik want to match this speed value with a speed value in a array where speeds are linked to animals.
For example this is the array I have:
var animals = [
{
"speed": 33.7,
"animal": 'pig',
},
{
"speed": 40.2,
"animal": 'Dog',
},
{
"speed": 45.4,
"animal": 'Horse',
}
...
];
The speed value 42.9 is higher than the speed value of the dog in the array but lower than the speed value of the horse so I want the filter to turn the value 42.9 in to "Dog" so the end result wil be: You're faster than a Dog, instead of You're faster than a 42.9
I know how to call a filter but I don't know how build one.
Call filter: ng-bind="speed.value | speedToAnimal
filter:
app.filter('speedToAnimal', function() {
return function(input, optional1, optional2) {
// Do filter work here
return output;
}
});
jsfiddle
With some help from the answer of Amulya Kashyap this is my working solution:
<div ng-repeat="speed in speeds track by $index">
You're faster than a <span ng-bind="speed.value | speedToAnimal"></span>
</div>
The Filter a came up with:
app.filter('speedToAnimal', function () {
return function (value) {
var animals = [
{"speed":12,"animal":"Field Mouse"},
{"speed":13,"animal":"House Mouse"},
{"speed":16,"animal":"Camel"},
{"speed":18,"animal":"Pig"},
{"speed":20,"animal":"Gray Squirrel"},
{"speed":22,"animal":"Sea Lion"},
{"speed":24,"animal":"Sheep"},
];
if(!animals) return;
var curSpeed = value;
var len = animals.length - 1;
while(len >= 0){
if(curSpeed >= animals[len].speed){
return animals[len].animal;
}
len--;
}
};
});
Here's the working Fiddle of your code.
Now, here is your code too :
HTML PART :
<div ng-controller="MyCtrl">
<legend> Enter Speed</legend>
<input type="text" ng-model="speed.value" required />
<button type="button" ng-click="calc()">Get Animal</button>
<span>{{filteredAnimals}}</span>
</div>
CONTROLLER CODE
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function($scope) {
$scope.animals = [
{
"speed": 33.7,
"animal": 'pig',
},
{
"speed": 40.2,
"animal": 'Dog',
},
{
"speed": 45.4,
"animal": 'Horse',
}];
$scope.calc = function(){
$scope.curSpeed = $scope.speed.value;
var len = $scope.animals.length - 1;
var filteredAnimals;
while(len >= 0){
if($scope.curSpeed >= $scope.animals[len].speed){
filteredAnimals = $scope.filteredAnimals = $scope.animals[len].animal;
break;
}
len--;
}
}
});

Angular.js count item iterations when filtering objects with ng-options

working on a list filtering with Angular, where listing the items based on region and creating an option select to list these regionsm where I have to remove duplications, and will need a count number next to the region name, which represents how many items from the same region.
I found this thread : How to count unique results based on a particular properties within ng-options but its not working when removing the duplications.
Heres is my select
<select ng-options="item.region as item.region for item in items | unique: 'region'" ng-model="catFilter">
Here is my app.js
var regionSort = angular.module('regionSort', [
'regionSort.controllers'
]);
regionSort.filter('unique', function() {
return function(items, filterOn) {
if (filterOn === false) {
return items;
}
if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
var hashCheck = {},
newItems = [];
var extractValueToCompare = function(item) {
if (angular.isObject(item) && angular.isString(filterOn)) {
return item[filterOn];
} else {
return item;
}
};
angular.forEach(items, function(item) {
var valueToCheck, isDuplicate = false;
var count = 0;
for (var i = 0; i < newItems.length; i++) {
if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
newItems.push(item);
}
});
items = newItems;
}
return items;
};
});
Does anybody have any idea how should I solve this? Thanks in advance!!
Item structure is pretty simple like :
[
{
"name": "Name",
"desc": "Description",
"price": 700,
"priceold": 1080,
"persons": 10,
"discount": 35,
"vote": "9,3",
"image": "https://someige.jpg",
"url": "http://someurl.com",
"region": "XXX"
}, ...
]

Dynamic angular chart

I'm trying to create a dynamic chart from userTemplate object.
I'm using this directive angular-flot and I want create the dataset and options of directive dynamically.
Its work but I have this error
Error: [$rootScope:infdig] http://errors.angularjs.org/1.2.21/$rootScope/infdig?p0=10&p1=%5B%5B%22fn%3…ection%5C%22%3A%7B%5C%22color%5C%22%3A%5C%22%2354728c%5C%22%7D%7D%22%5D%5D
at Error (native)
at http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:6:450
at k.$get.k.$digest (http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:110:66)
at k.$get.k.$apply (http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:112:173)
at http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:122:253
at e (http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:37:440)
at http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:41:120
HTML
<div ng-repeat="panel in row.panels" class="{{panel.columnClass}}" resizable id="{{panel.id}}" r-directions="['right']">
<flot dataset="getDataForChart(panel)" options="getOptionForChart(panel)" height="{{panel.graph.height}}"></flot>
</div>
CONTROLLER
$scope.userTemplate = [
{
blockId: 'blockUno',
title: 'Block title',
rows: [
{
rowId: 'rowUno',
title: 'Row Title 1',
panels: [
{
id: 'palel-report-1',
title: 'uno',
columnClass: 'col-md-4',
graph: {
height: 250,
type: "BAR",
countBy: "status"
}
},
{
id: 'palel-report-2',
title: 'due',
columnClass: 'col-md-4',
graph: {
height: 250,
type: "PIE",
countBy: "status"
}
},
{
id: 'palel-report-3',
title: 'tre',
columnClass: 'col-md-4',
graph: {
height: 250,
type: "BAR",
countBy: "status"
}
}
]
}
],
tables: []
}
];
$scope.getDataForChart = function(panel) {
var graphData = [];
var countBy = panel.graph.countBy;
var arr = $scope.reportingData;
for (var i = 0; i < arr.length; i++) {
var valueOfkey = arr[i][countBy];
graphData.push(valueOfkey);
}
var a = [], b = [], prev;
graphData.sort();
for (var i = 0; i < graphData.length; i++) {
if (graphData[i] !== prev) {
a.push(graphData[i]);
b.push(1);
} else {
b[b.length - 1]++;
}
prev = graphData[i];
}
var graphData = [];
for (var i = 0; i < a.length; i++) {
var singleO = {label: '' + a[i], data: [[i, b[i]]]};
graphData.push(singleO);
}
return graphData;
};
$scope.getOptionForChart = function(panel) {
var options = angular.copy($scope.defaultPlotOptions);
var typeGraph = panel.graph.type;
switch (typeGraph) {
case "BAR":
options.series.bars.show = true;
break;
case "LINE":
options.series.lines.show = true;
break;
case "PIE":
options.series.pie.show = true;
break;
case "POINT":
options.series.points.show = true;
break;
case "TABLE":
break;
}
return options;
};
The error you get is from an infinite digest loop.
In a couple of places you are calling functions that return new items each time. Here's an example from the docs linked from the error message you received that suggests this may cause this error:
One common mistake is binding to a function which generates a new
array every time it is called. For example:
<div ng-repeat="user in getUsers()">{{ user.name }}</div>
$scope.getUsers = function() { return [ { name: 'Hank' }, { name: 'Francisco' } ]; };
Since getUsers() returns a new array, Angular
determines that the model is different on each $digest cycle,
resulting in the error. The solution is to return the same array
object if the elements have not changed:
var users = [ { name: 'Hank' }, { name: 'Francisco' } ];
$scope.getUsers = function() { return users; };
In your code, you are doing the same binding to getDataForChart and getOptionForChart.

Resources