ng-show is not working with ng-repeat - angularjs

Below is my table markup
<tr ng-show="paginate({{$index+1}})" ng-repeat="x in ProductInfo_Pager | orderBy :sortType:sortReverse | filter:searchText | limitTo : rowPerPage" ng-class="$even?'table-danger':'table-info'">
<td>{{$index+1}}</td>
<td>{{x.Product}}</td>
<td>{{x.Location}}</td>
<td>{{x.Qty}}</td>
<td>{{x.UnitPrice | currency : '₹':2}}</td>
<td class="text-center">
<i class="fa fa-flag" aria-hidden="true" style="color:red" /> |
<i class="fa fa-bolt" aria-hidden="true" style="color:red" /> |
<i class="fa fa-users" aria-hidden="true"></i>
</td>
</tr>
and pager below it
<ul class="pagination">
<li class="page-item" ng-repeat="x in getNumber(rowPerPage) track by $index">
<a class="page-link" ng-click="pagerIndex=$index+1">{{$index+1}}</a>
</li>
</ul>
And AngularJs Code
$scope.ProductInfo_Pager = $scope.ProductInfo;
$scope.sortType = 'Product'; // set the default sort type
$scope.sortReverse = false; // set the default sort order
$scope.searchText = ''; // set the default search/filter term ,
$scope.totalItems = $scope.ProductInfo.length;
$scope.currentPage = 1;
$scope.rowPerPage = 5;
$scope.pagerIndex = 1;
$scope.getNumber = function (num) {
var pages = $window.Math.ceil($scope.totalItems / num);
return new Array(pages);
}
$scope.paginate = function (rowindex) {
var begin, end, index, flag ;
index = $scope.pagerIndex;
end = (index * $scope.rowPerPage) - 1; // -1 to sync it with zero based index
begin = end - $scope.rowPerPage + 1;
if(rowindex >=begin && rowindex <= end ){
flag=true;
}
else{
flag=false;
}
var d = 0;
return flag;
};
paginate function() return true or false based on logic which is used in ng-show in tr tag with ng-repeat, but its not doing show , hide functionality as expected
Logic is :
Suppose rowPerPage is 5 - [5 row can be show up in table at a time]
And we click on 4 in pager so it should show row from 16-20 .
In ng-show paginate function is bind which take row index as parameter , this function check if rowindex falls in between 16 - 20 , if yes than it return true (ng-show=true) else false and accordingly should hide that row.
As per mu understanding its two way binding so any change in ng-show should work perfectly but it does not show any effect
Can someone help me why this is happening
I am a newbie in angularjs
Thanks.

Well ! ng-show is not working here and the function is not getting called at all written in ng-show !
If i correctly understand you want to create a pagination :
So i am giving you a very simple solution of pagination using a pagination filter .
you need to add this filter to your app :
app.filter('pagination', function() {
return function(input, start) {
start = +start; //parse to int
if (input != undefined && Object.keys(input).length > 0) {
return input.slice(start);
}
}
});
In your html :
<tr ng-repeat="x in ProductInfo_Pager | pagination: currentPage * rowPerPage | limitTo: rowPerPage|orderBy :sortType:sortReverse | filter:searchText" ng-class="$even?'table-danger':'table-info'">
<td>{{$index+1}}</td>
<td>{{x.Product}}</td>
<td>{{x.Location}}</td>
<td>{{x.Qty}}</td>
<td>{{x.UnitPrice | currency : '₹':2}}</td>
<td class="text-center">
<i class="fa fa-flag" aria-hidden="true" style="color:red" /> |
<i class="fa fa-bolt" aria-hidden="true" style="color:red" /> |
<i class="fa fa-users" aria-hidden="true"></i>
</td>
</tr>
In your pagination ul below your table :
<ul class="pagination">
<li class="page-item" ng-repeat="x in getNumber(rowPerPage) track by
$index">
<a class="page-link" ng-click="pagerIndex=$index+1">{{$index+1}}
</a>
</li>
</ul>
in your controller :
$scope.numberOfPages = function() {
if ($scope.ProductInfo_Pager != undefined) {
return Math.ceil($scope.ProductInfo_Pager.length /
$scope.rowPerPage);
}
};
Hope it work ! if any doubt please let me know .

Related

angular 1.5 orderBy doesn't work

I have an array with objects in it which I would like to sort within my ng-repeat, but no matter which field I get it doesn't seem to respond to anything.
I have the following array:
[{"title":"test 2","planId":"waUVOGARMUyScTYtHI2p_5cAEI_f","dueDate":"","status":0,"assigneePriority":"85868377FP","planTitle":"plan 2","ownerId":"3c9a3683-5057-4e28-b348-0e1f23157bec"},{"title":"Visit the VET","planId":"PyHP00vnzkqxyheVWMOqhZcAFU0F","dueDate":"21-02","status":0,"assigneePriority":"85868377E(","planTitle":"Groep_test23","ownerId":"5cfb5e90-c5d1-4c83-acca-d86e4b912a0c"},{"title":"test","planId":"waUVOGARMUyScTYtHI2p_5cAEI_f","dueDate":"","status":0,"assigneePriority":"85868376\\:","planTitle":"plan 2","ownerId":"3c9a3683-5057-4e28-b348-0e1f23157bec"}]
The controller code:
function getAllTasks() {
datacontext.graph.plannerGetAllTasks().then(function (tasks) {
datacontext.graph.plannerGetAllPlans().then(function (plans) {
var totalTasks = tasks.length;
for (var i = 0; i < totalTasks; i++) {
// append the plan name, owner Id to the tasks object.
var totalPlans = plans.length;
for (var j = 0; j < totalPlans; j++) {
if (plans[j].planId.indexOf(tasks[i].planId) != -1) {
tasks[i].planTitle = plans[j].title;
tasks[i].ownerId = plans[j].ownerId;
}
}
vm.tasks.push(tasks[i]);
}
changeListBucket(vm.currentTab);
});
});
}
and this is my html:
<div class="newsroom-tabs-bottom">
<a class="list-group-item newsItem-pointer" ng-repeat="task in vm.tasksToShow | limitTo: vm.amountOfTasksToShow | orderBy: task.planTitle">
<table style="width: 100%" class="dont-break-out">
<tr>
<td class="planner-icon-set-fixed-width default-text-colour">
{{$index + 1}}
</td>
<td style="width: 100%">
<span>
<span class="list-inbox-info-from-teamnews dont-break-out default-text-colour">{{::task.title}}</span>
</span>
<span class="list-inbox-info-subject dont-break-out default-text-colour">
{{::task.planTitle}}
<span style="float: right">{{ ::task.dueDate }}</span>
</span>
</td>
</tr>
</table>
</a>
</div>
I have checked the following post but none of the solutions worked for me. (Angular - Can't make ng-repeat orderBy work)
any help would be much appreciated. Cheers!
Jus use planTitle
<a class="list-group-item newsItem-pointer" ng-repeat="task in vm.tasksToShow | limitTo: vm.amountOfTasksToShow | orderBy: 'planTitle'">

AngularJS - orderBy value when ng-repeat by key, value pair

I have counted the ocurrences of each item in a set of data with countBy function in lodash, and the result is this:
$scope.colors= {
"Orange": 3,
"Blue": 2,
"Pink": 1,
"Red": 1,
"Black": 2,
};
Now I would like to display the data and order it by its value. I've tried with
<div ng-controller="myCtrl" ng-app="myApp">
<ul>
<li ng-repeat="(key,value) in colors | orderBy:value">
{{key}} ({{value}})
</li>
</ul>
</div>
But the orderBy filter doesn't seem to do the trick (see the plunkr here)
Is there any way to do it with the current data form, or is it a better way to structure the data in order to achieve the desired result? Thanks in advance!
As the documentation says, orderBy expects an array as input, not an object. In general, although it's supported, I've never met a use-case where using an object with ng-repeat was a good idea.
Just transform your object into an array:
$scope.colors = [];
angular.forEach(occurrences, function(value, key) {
$scope.colors.push({
color: key,
count: value
});
});
and then use
<li ng-repeat="element in colors | orderBy:'count'">
{{ element.color }} ({{ element.count }})
</li>
See your updated plunkr.
After multiple tries, I found a way to iterate an object and have it ordered by the key.
<div ng-repeat="key1 in keys(obj1) | orderBy: key1">
I would instead use an array like so:
colors = [{color: 'red', value: 1}, {color: 'blue', value: 2}]
Then you can use
ng-repeat="color in colors | orderBy:'value'"
Plunkr
different approach - for
string from JsonConvert.SerializeObject(DataTable), so basically List<Dictionary<string, string>>
Example is combination of few solutions (sorry for no references)
In AngularJs controller:
vm.propertyName = '\u0022Spaced Column Name\u0022';
vm.reverse = true;
vm.sortBy = function (propertyName) {
vm.reverse = (vm.propertyName === '\u0022' + propertyName +'\u0022') ? !vm.reverse : false;
vm.propertyName = '\u0022' + propertyName + '\u0022';
};
vm.Data = JSON.parse(retValue.Data);
for (var i = 0; i < vm.Data.length; i++) {
var obj = {};
angular.forEach(vm.Data[i], function (value, key) {
obj[key] = value;
});
vm.DataArr.push(obj);
}
By ng-if="key != 'Id'" I'm hiding Id column with Guid
And then in html:
<table border="1">
<tr>
<td ng-repeat="(key, value) in vm.Data[0]" ng-if="key != 'Id'">
<button ng-click="vm.sortBy(key)">{{key}}</button>
<span ng-show="vm.propertyName == '\u0022'+key+'\u0022' && !vm.reverse" class="fa fa-arrow-up"></span>
<span ng-show="vm.propertyName == '\u0022'+key+'\u0022' && vm.reverse" class="fa fa-arrow-down"></span>
</td>
</tr>
<tr ng-repeat="row in vm.DataArr |orderBy:vm.propertyName:vm.reverse track by $index" ng-init="rowInd0 = $index">
<td ng-repeat="(key, value) in vm.Data[0]" ng-if="key != 'Id'">
<span>{{row[key]}}</span>
</td>
</tr>
</table>

Cart calculations in AngularJS

I'm just starting out with AngularJS attempting to build a shopping cart.
Below is my code.
Items.html
<li id="{{item.id}}" ng-click="addItem(item)" class="menu-item" ng-repeat="item in items">
<span class="list-item-inner">
<span class="item-content">
<span class="vc-outer">
<span class="vc-inner">
<span class="list-item-title" style="color: #3F4B56; font-size: 1.1rem;"
ng-bind="item.name">
</span>
<span class="list-item-description" style="font-size: 0.9rem; color: #6B7781;" ng-bind="item.description">
</span>
</span>
</span>
</span>
</span>
<span class="item-price">
<span class="vc-outer">
<span class="vc-inner no-wrap"
ng-bind="'₦' + (item.price)"></span>
</span>
</span>
<span class="item-add"></span>
</li>
Cart.html
<li class="has-counter order-item" ng-class="{'has-modifier' : cart.length}" ng-repeat="item in cart">
<div class="counter-control-vertical is-editable">
<div class="controls"> <a href="" class="control ctrl-up" ng-click="incQty(item)" style="text-decoration: none;">
+
</a>
<a href="" class="control ctrl-down" ng-click="decQty(item)" style="text-decoration: none;">
–
</a>
</div>
</div>
<div class="oi-inner">
<div class="oi-details" ng-click="editModifiers(item)">
<div class="oi-quantity" ng-bind="(item.count) +'x'"></div>
<div class="oi-title" ng-bind="item.name"></div>
<div class="oi-modifiers"></div>
</div>
<div class="oi-price" ng-bind="'₦' + (item.price)"></div> ×
</div>
</li>
Cart.js
// Array containing my items.
$scope.itemData = <? php echo json_encode($item_array); ?> ;
$scope.cart = [];
$scope.deleteItem = function (item) {
var cart = $scope.cart;
var match = getMatchedCartItem(item);
if (match.count > 0) {
cart.splice(cart.indexOf(item));
return;
}
}
$scope.addItem = function (item) {
var match = getMatchedCartItem(item);
if (match) {
match.count += 1;
return;
}
var itemToAdd = angular.copy(item);
itemToAdd.count = 1;
$scope.cart.push(itemToAdd);
}
$scope.incQty = function (item) {
var match = getMatchedCartItem(item);
if (match) {
match.count += 1;
return;
}
}
$scope.decQty = function (item) {
var cart = $scope.cart;
var match = getMatchedCartItem(item);
if (match.count > 1) {
match.count -= 1;
return;
}
cart.splice(cart.indexOf(item), 1);
}
At the moment I can add, remove, increment and decrement items in the cart array and display them in realtime. But the price does not change based on qty.
My question is;
How can I calculate and display price based on qty of an item in cart?
How do I calculate total price of all the items in the cart array?
ng-bind="item.price * item.count"
I would call a function (witch calculates the total price) every time you change the cart and store the result in an new variable.
$scope.calcTotal = function() {
var total=0;
for (var i = 0, max = $scope.cart.length; i < max; i++) {
total += $scope.cart[i].price * $scope.cart[i].count;
}
$scope.total = total;
}

AngularJS - How to access to the next item from a ng-repeat in the controller

I'd like to access to the parameters of the next item on screen when clicking on a button.
I use a ng-repeat in my html file:
<li ng-repeat="item in items | filter:query" ng-show="isSelected($index)">
<img src="xxx.jpg" />
</li>
And the index in my Controller with a loop:
$scope.itemNext = function () {
$scope._Index = ($scope._Index < $scope.nbItems - 1) ? ++$scope._Index : 0;
$scope.functionToCallWithNextItem(nextItem.param1);
};
A simple $scope.items[$scope._Index].param1 instead of nextItem.param1 wouldn't work as the data is filtered so $index+1 from $scope.items isn't necessarily the good one.
Any idea ?
You can assign your filtered data to a variable:
<li ng-repeat="item in (filteredItems = (items | filter:query))">
Then use $index + 1 to get the next item:
<a ng-click="itemNext(filteredItems[$index + 1])">
Demo: http://plnkr.co/edit/OdL5rIxtTEHnQCC3g4LS?p=preview
It's simpy that
<div ng-repeat="item in items">
current: {{item.value}}
next: {{ items[$index + 1].value}}
previous: {{ items[$index - 1].value}}
</div>

Filter results 6 through 10 of 100 with ng-repeat in AngularJS

I see the limitTo filter in the docs, which allows me to limit the first 5, or last 5 results, but I want to set where my limit starts so I can show the second set of 5 results.
Is there a built in filter for that?
Since Angular 1.4.0, the limitTo filter takes an optional begin argument:
<div ng-repeat="item in items | limitTo:5:5">{{item}}</div>
In older versions, writing a custom filter is fairly straightforward. Here's a naïve implementation based on Array#slice (note you pass the first and last index, instead of a count):
app.filter('slice', function() {
return function(arr, start, end) {
return (arr || []).slice(start, end);
};
});
<div ng-repeat="item in items | slice:6:10">{{item}}</div>
Working jsFiddle: http://jsfiddle.net/BinaryMuse/vQUsS/
Alternatively, you can simply steal the entire Angular 1.4.0 implementation of limitTo:
function limitToFilter() {
return function(input, limit, begin) {
if (Math.abs(Number(limit)) === Infinity) {
limit = Number(limit);
} else {
limit = toInt(limit);
}
if (isNaN(limit)) return input;
if (isNumber(input)) input = input.toString();
if (!isArray(input) && !isString(input)) return input;
begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
begin = (begin < 0 && begin >= -input.length) ? input.length + begin : begin;
if (limit >= 0) {
return input.slice(begin, begin + limit);
} else {
if (begin === 0) {
return input.slice(limit, input.length);
} else {
return input.slice(Math.max(0, begin + limit), begin);
}
}
};
}
AngularJS provides that functionality already out of the box. If you carefully read the limitTo documentation it allows you to specify a negative value for the limit. That means N elements at the end so if you want to process 5 results after an offset of 5 you need to do the following:
<div ng-repeat="item in items | limitTo: 10 | limitTo: -5">{{item}}</div>
I started playing around with customer filters but then found out you can just call slice inside of the ng-repeat expression:
<div ng-repeat="item in items.slice(6, 10)">{{item}}</div>
As bluescreen said, it can be done using only the limitTo filter, although dealing with the last page problem noticed by Harry Oosterveen needs some extra work.
I.e. using ui-bootstrap pagination directive properties:
ng-model = page // current page
items-per-page = rpp // records per page
total-items = count // total number of records
The expression should be:
<div ng-repeat="item in items | limitTo: rpp * page | limitTo: rpp * page < count ? -rpp : rpp - (rpp * page - count)">{{item}}</div>
Here's a functional example on how to filter a list with offset and limit:
<!doctype html>
<html lang="en" ng-app="phonecatApp">
<head>
<script src="lib/angular/angular.js"></script>
<script src="js/controllers.js"></script>
</head>
<body ng-controller="PhoneListCtrl">
Offset: <input type="text" ng-model="offset" value="0" /><br />
Limit: <input type="text" ng-model="limit" value="10" /><br />
<p>offset limitTo: {{offset - phones.length}}</p>
<p>Partial list:</p>
<ul>
<li ng-repeat="phone in phones | limitTo: offset - phones.length | limitTo: limit">
{{$index}} - {{phone.name}} - {{phone.snippet}}
</li>
</ul>
<hr>
<p>Whole list:</p>
<ul>
<li ng-repeat="phone in phones">
{{$index}} - {{phone.name}} - {{phone.snippet}}
</li>
</ul>
</body>
</html>
The example is based on the second step of AngularJS tutorial.
Note that the filter for the offset has to be put as the first filter if you want to cover the generic case where the limit is uknnown.
from bluescreen answer :
<div ng-repeat="item in items | limitTo: 10 | limitTo: -5">{{item}}</div>
you might also find a scenario where you need to take N-th item till the last item, this is another way using limitTo:
<div ng-repeat="item in items | limitTo:-(items.length-5)>{{item}}</div>
negative sign will take as much as items.length from last, then minus 5 inside the bracket will skip the first 5 items
There's a tidier way to do it without having to invoke a filter and will behave more like a paginator:
$scope.page = 0;
$scope.items = [ "a", "b", "c", "d", "e", "f", "g" ];
$scope.itemsLimit = 5;
$scope.itemsPaginated = function () {
var currentPageIndex = $scope.page * $scope.itemsLimit;
return $scope.items.slice(
currentPageIndex,
currentPageIndex + $scope.itemsLimit);
};
And just stick that in your view:
<ul>
<li ng-repeat="item in itemsPaginated() | limitTo:itemsLimit">{{item}}</li>
</ul>
Then you can just increment/decrement $scope.page:
$scope.page++;
You can also create your own reusable filter startFrom like so:
myApp.filter('startFrom', function () {
return function (input, start) {
start = +start;
return input.slice(start);
}
});
and then use it in your ng-repeat like so:
ng-repeat="item in items | startFrom: 5 | limitTo:5
That way it is done "in a spirit of AngularJs filters", testable, can have some "extra" logic if needed, etc.
#bluescreen's ans and #Brandon's ans are not equivalent.
for example:
var pageSize = 3;
var page = 2;
var items = [1, 2, 3, 4];
--
item in items | limitTo: page*pageSize | limitTo: -1*pageSize
produce [2, 3, 4]
item in items | slice: (page-1)*pageSize : page*pageSize
produce [4]
For Ionic based projects find the solution below:
mainpage.html:
<ion-view view-title="My Music">
<ion-content>
<ion-list>
<ion-item ng-repeat="track in tracks | limitTo: limit | limitTo: -10 ">
{{track.title}}
</ion-item>
</ion-list>
<div class="list"></div>
<div align="center">
<button class="button button-small button-positive" ng-disabled="currentPage == 0" ng-click="decrementLimit()">
Back
</button>
<button class="button button-small button-energized">
{{currentPage+1}}/{{numberOfPages()}}
</button>
<button class="button button-small button-positive" ng-disabled="currentPage >= data_length/pageSize - 1" ng-click="incrementLimit()">
Next
</button>
</div>
</ion-content>
</ion-view>
controller.js:
var myApp = angular.module('musicApp.controllers', []);
myApp.controller('AppCtrl', function($scope, $http) {
console.log('AppCtrl called');
// $scope.tracks = MusicService.query();
$http.get('api/to/be/called').then(function(result){
$scope.tracks = result.data['results'];
$scope.data_length = $scope.tracks.length;
console.log(result)
// console.log($sco pe.tracks.length)
});
var currentPage = 0;
$scope.pageSize = 10;
$scope.numberOfPages = function(){
return Math.ceil($scope.tracks.length/$scope.pageSize);
}
var limitStep = 10;
$scope.limit = limitStep;
$scope.currentPage = currentPage;
$scope.incrementLimit = function(){
$scope.limit += limitStep;
$scope.currentPage += 1
};
$scope.decrementLimit = function(){
$scope.limit -= limitStep;
$scope.currentPage -= 1
}
});

Resources