please help to fix the script.
http://jsfiddle.net/rrnJc/
this is a dynamic list of news. you can scroll through.
the problem that the logic is in the template:
<li ng-repeat="item in news" ng-show="$index >= currentPosition && $index <= (currentPosition + qntVisibleRecords)">
this is not right.
I would like to chtby visible part of the list of news was in the controller (in the function $scope.newsVisible). at the same conclusion in the template design and deliver this:
<li ng-repeat="item in newsVisible">
<span class="date">{{item.date}}</span>
<span class="title">{{item.title}} - {{$index}}</span>
</li>
Just slice your array of news when controller is initialized and each time you call the changeCurrent function and iterate through newsVisible. Possible code could be :
$scope.changeCurrent = function(value){
$scope.currentPosition = $scope.currentPosition + value;
if($scope.currentPosition < 0 ){
$scope.currentPosition = 0;
}
var end = Math.min($scope.currentPosition + $scope.qntVisibleRecords, $scope.news.length)
//ensure that you won t slice at an index greater than news.length
$scope.newsVisible = $scope.news.slice($scope.currentPosition, end);
}
BTW you can call this function when the controller initialized in order to init your array of newsVisible.
$scope.changeCurrent($scope.currentPosition);
You can check it here http://jsfiddle.net/rrnJc/1/
Related
I have this code. $scope.counter = '1';
<div ng-repeat="cat in catadata">
<div ng-if="cat.TopCategoryID = 2" >
<div ng-if="counter = 1" >
<div class="feedsDisplay" ng-init="counter = counter + 1">
Creater Img:{{cat.CreatedBy_Profile.Picture.URI}}"
</div>
</div>
</div>
</div>
I want to stop loop when counter = 2, I want to display just 1 result.
ng-init="counter = counter + 1
{{counter}}
displaying 11111 it should display 12345
you are comparing with = instead of ==
Try like this
ng-if="counter == 1"
value of counter is string . add + sign before counter
try like this
ng-init="counter = +counter + 1"
You cant stop ng-repeat conditionally.
To print only one result you can use
<div ng-repeat="cat in catadata | limitTo : 1">
OR
<div>{{catadata[0]}}</div>
Rather than misusing ng-repeat, ng-init and ng-if like this, just try to extract the first matching cat before you render it, e.g. in a controller, directive or service:
for (var i = 0, maxI = catadata.length; i < maxI; ++i) {
if (cat.TopCategoryID === 2) {
$scope.firstMatchingCat = cat;
break;
}
}
And then in the template:
<div class="feedsDisplay">
Creater Img:{{firstMatchingCat.CreatedBy_Profile.Picture.URI}}"
</div>
I have a condition that needs to be checked in my view: If any user in the user list has the same name as another user, I want to display their age.
Something like
<div ng-repeat="user in userList track by $index">
<span class="fa fa-check" ng-if="user.isSelected"></span>{{user.firstName}} <small ng-if="true">{{'AGE' | translate}} {{user.age}}</small>
</div>
except I'm missing the correct conditional
You should probably run some code in your controller that adds a flag to the user object to indicate whether or not he/she has a name that is shared by another user.
You want to minimize the amount of logic there is inside of an ng-repeat because that logic will run for every item in the ng-repeat each $digest.
I would do something like this:
controller
var currUser, tempUser;
for (var i = 0; i < $scope.userList.length; i++) {
currUser = $scope.userList[i];
for (var j = 0; j < $scope.userList.length; j++) {
if (i === j) continue;
var tempUser = $scope.userList[j];
if (currUser.firstName === tempUser.firstName) {
currUser.showAge = true;
}
}
}
html
ng-if='user.showAge'
Edit: actually, you probably won't want to do this in the controller. If you do, it'll run every time your controller loads. You only need this to happen once. To know where this should happen, I'd have to see more code, but I'd think that it should happen when a user is added.
You can simulate a hashmap key/value, and check if your map already get the property name. Moreover, you can add a show property for each objects in your $scope.userList
Controller
(function(){
function Controller($scope) {
var map = {};
$scope.userList = [{
name:'toto',
age: 20,
show: false
}, {
name:'titi',
age: 22,
show: false
}, {
name: 'toto',
age: 22,
show: false
}];
$scope.userList.forEach(function(elm, index){
//if the key elm.name exist in my map
if (map.hasOwnProperty(elm.name)){
//Push the curent index of the userList array at the key elm.name of my map
map[elm.name].push(index);
//For all index at the key elm.name
map[elm.name].forEach(function(value){
//Access to object into userList array with the index
//And set property show to true
$scope.userList[value].show = true;
});
} else {
//create a key elm.name with an array of index as value
map[elm.name] = [index];
}
});
}
angular
.module('app', [])
.controller('ctrl', Controller);
})();
HTML
<body ng-app="app" ng-controller="ctrl">
<div ng-repeat="user in userList track by $index">
<span class="fa fa-check"></span>{{user.name}} <small ng-if="user.show">{{'AGE'}} {{user.age}}</small>
</div>
</body>
Please see this JS fiddle link.
http://jsfiddle.net/4Dpzj/174/
This is the logic for group by
app.filter('groupBy', ['$parse', function ($parse) {
return function (list, group_by) {
var filtered = [];
var prev_item = null;
var group_changed = false;
// this is a new field which is added to each item where we append "_CHANGED"
// to indicate a field change in the list
//was var new_field = group_by + '_CHANGED'; - JB 12/17/2013
var new_field = 'group_by_CHANGED';
// loop through each item in the list
angular.forEach(list, function (item) {
group_changed = false;
// if not the first item
if (prev_item !== null) {
// check if any of the group by field changed
//force group_by into Array
group_by = angular.isArray(group_by) ? group_by : [group_by];
//check each group by parameter
for (var i = 0, len = group_by.length; i < len; i++) {
if ($parse(group_by[i])(prev_item) !== $parse(group_by[i])(item)) {
group_changed = true;
}
}
}// otherwise we have the first item in the list which is new
else {
group_changed = true;
}
// if the group changed, then add a new field to the item
// to indicate this
if (group_changed) {
item[new_field] = true;
} else {
item[new_field] = false;
}
filtered.push(item);
prev_item = item;
});
return filtered;
};
I want to group all the products together.
what changes i need to do ?
I come up with this in my mind. Without using any custom filters.
I simply use this ng-repeat syntax :
ng-repeat="(key,item) in MyList | orderBy:orderKey"
Thanks to it i can get the key to compare the value with the previous object.
Here is my ng-show attribute. It can be improved by sorting the list somewhere else (like in the controller)
<h2 ng-show="(MyList | orderBy:orderKey)[key-1][orderKey] !== (MyList | orderBy:orderKey)[key][orderKey]"
Thanks to this you can populate your var "orderKey" with any of your attribute name and this will works.
See it working in this JSFiddle
Hope it helped.
EDIT :
I think it would be a bit cleaner to use a temporary list to manage the visual order (see it in this JSFiddle):
JS :
$scope.orderList = function(){
$scope.orderedList = $filter('orderBy')($scope.MyList,$scope.orderKey);
}
HTML :
ng-change="orderList()" To trigger the list sort
The cleaner ng-repeat / ng-show
<div ng-repeat="(key,item) in orderedList">
<h2 ng-show="orderedList[key-1][orderKey] !== orderedList[key][orderKey]">{{item[orderKey]}} </h2>
<ul>
<li>{{item.ProductName}}</li>
</ul>
</div>
Have a look at this:
http://jsfiddle.net/4Dpzj/176/
<div ng-repeat="item in MyList | orderBy:['SubCategoryName','BrandName'] | groupBy:['SubCategoryName']" >
<h2 ng-show="item.group_by_CHANGED">{{item.SubCategoryName}} </h2>
<ul>
<li>{{item.ProductName}} --- {{item.BrandName}}</li>
</ul>
</div>
I'll preface this by saying I am very new to AngularJS so forgive me if my mindset is far off base. I am writing a very simple single page reporting app using AngularJS, the meat and potatoes is of course using the angular templating system to generate the reports themselves. I have many many reports that I am converting over from a Jinja-like syntax and I'm having a hard time replicating any kind of counter or running tabulation functionality.
Ex.
{% set count = 1 %}
{% for i in p %}
{{ count }}
{% set count = count + 1 %}
{% endfor %}
In my controller I have defined a variable like $scope.total = 0; which I am then able to access inside of the template without issue. What I can't quite figure out is how to increment this total from within an ng-repeat element. I would imagine this would look something like -
<ul>
<li ng-repeat="foo in bar">
{{ foo.baz }} - {{ total = total + foo.baz }}
</li>
</ul>
<div> {{ total }} </div>
This obviously doesn't work, nor does something like {{ total + foo.baz}}, thanks in advance for any advice.
If all you want is a counter (as per your first code example), take a look at $index which contains the current (0 based) index within the containing ngRepeat. And then just display the array length for the total.
<ul>
<li ng-repeat="item in items">
Item number: {{$index + 1}}
</li>
</ul>
<div>{{items.length}} Items</div>
If you want a total of a particular field in your repeated items, say price, you could do this with a filter, as follows.
<ul>
<li ng-repeat="item in items">
Price: {{item.price}}
</li>
</ul>
<div>Total Price: {{items | totalPrice}}</div>
And the filter function:
app.filter("totalPrice", function() {
return function(items) {
var total = 0, i = 0;
for (i = 0; i < items.length; i++) total += items[i].price;
return total;
}
});
Or, for improved reusability, a generic total filter function:
app.filter("total", function() {
return function(items, field) {
var total = 0, i = 0;
for (i = 0; i < items.length; i++) total += items[i][field];
return total;
}
});
Which would be used like:
<div>Total price: {{items | total:'price'}}</div>
I needed running total rather that plain total, so I've added upon what #TimStewart left. Here the code:
app.filter("runningTotal", function () {
return function(items, field, index) {
var total = 0, i = 0;
for (i = 0; i < index+1; i++) {
total += items[i][field];
}
return total;
};
});
To use it in column you just do:
<div>Total price: {{items | runningTotal:'price':$index}}</div>
I'm not sure I totally understand the question, but are just needing to display the total number in the object you're iterating over? Just set $scope.total to the length of your array (bar in your example above). So, $scope.total = $scope.bar.length;
If you're wanting the total of all the foo.baz properties, you just need to calculate that in your controller.
$scope.total = 0;
angular.forEach($scope.bar, function(foo) {
$scope.total += foo.baz;
});
I have the following HTML with a value of "1-99" visible:
<ul class="controls-buttons question-controls">
<li>
</li>
<li>
<a id="orderRange">1 - 99</a>
</li>
<li>
<img src="/Images/control-double.png">
</li>
</ul>
Is there a way that I can have the orderRange change so it changes like this when the previous and next links are clicked? Ideally I would like some way that doesn't mean I have to hardcode a lot of if and else statements.
1-99 > 100-199
1-99 < 100-199 > 200-299
100-199 < 200-299 > 300-399
200-299 < 300-399
etc ..
Once changed I would like to store the value using local storage like below:
var store = window.localStorage;
store.setItem('Range', xxx)
I hope someone can help me.
Here's a solution :
function change(d) {
var $field = $('#orderRange');
var nums = $field.text().split('-').map(function(a){return parseInt(a,10)+d*100});
if (nums[0]<0) return;
else if (nums[0]==101) nums[0]=100;
else if (nums[0]==0) nums[0]=1;
$field.html(nums.join(" - "));
}
$('#orderPrevious').click(function(){change(-1)});
$('#orderNext').click(function(){change(+1)});
Demonstration
function changeRange(delta){
var orderRange=document.getElementById('orderRange'),
range=orderRange.innerHTML.split(' - ')
range=[parseInt(range[0])+delta,parseInt(range[1])+delta]
if(range[0]<0) return
orderRange.innerHTML=range.join(' - ')
var store = window.localStorage;
store.setItem('Range', orderRange.innerHTML)
}
document.getElementById('orderNext').onclick=function(){changeRange(100);}
document.getElementById('orderPrevious').onclick=function(){changeRange(-100);}