ng-repeat on multiple arrays - angularjs

Is there a way to loop through multiple arrays in an ng-repeat directive ?
I tried something like
<ul>
<li ng-repeat="sale in randomSales" ng-repeat="image in imageUrls">
<div display-sale></div>
</li>
</ul>
or
<ul>
<li ng-repeat="sale in randomSales, image in imageUrls">
<div display-sale></div>
</li>
</ul>
but it's not working.
I could solve this issue another way, but I'd like to know if this is possible !
EDIT :
Here is my controller & directive :
app.controller('RandomController', ['$rootScope', '$scope',function($rootScope, $scope) {
$scope.randomSales=[];
$scope.imageUrls = [];
for(var i= 0; i < displayrandomSalesNumber ; i++){
var randomNumber = Math.floor((Math.random() * $rootScope.sales.length-1) + 1);
$scope.randomSales.push($rootScope.sales[randomNumber]);
$scope.imageUrls.push($rootScope.sales[randomNumber].image_urls["300x280"][0].url);
}
console.log($scope.randomSales);
}])
.directive('displaySale', function() {
return {
template: '<div class="center"><a href="#/sale/{{sale.store}}/{{sale.sale_key}}">' +
'<header><h2>{{sale.name}}</h2><h4>in {{sale.store}}</h4></header>' +
'<article>' +
'<p>From : {{sale.begins}} To : {{sale.ends}}</p>' +
'<p class="center"><img ng-src="{{image}}"/></p>' +
'<p>{{sale.description}}</p>' +
'</article>' +
'</a></div>'
};
});
the image is already inside $scope.randomSales, I could access it with {{sale.image_urls["300x280"][0].url}} but i'd get a parse error.

to make it work you can try to do following:
- merge 2 arrays to one arrays of objects representing imageUrls and randomSales.
- iterate though them in your template.
For example:
var maxArrayLength = Math.max(randomSales.length, imageUrls.length);
var i = 0;
var result = []; //will put items {sale: ..., image}
for (i =0; i < maxArrayLength; i++){
var currentSale = randomSales[i] != null ? randomSales[i] : null;
var currentImage = imageUrls[i] != null ? imageUrls[i] : null;
result.push({sale: currentSale, image: currentImage})
}
return result;
And them you can use this array to iterate through on your angular template.

The First Solution proposed by you is wrong , we cant have two ng-repeat attributes in one Html tag, I am not sure about the second one . But you could try like this ..i think it would work.
<ul>
<li ng-repeat="sale in randomSales">
<span ng-repeat="image in imageUrls">
<div display-sale></div>
</span>
</li>
</ul>

Related

AngularJS - Using custom filter in ng-repeat for prefixing comma

Need to remove comma if value is empty works good if I have value
present at start or middle; But same doesn't work in this scenario.
app.filter('isCSV', function() {
return function(data) {
return (data !== '') ? data + ', ' : '';
};
});
Angularjs ng repeat for addressline - Plunker
I would instead operate on arrays of properties and use a pair of filters, one to remove empty values, and one to join the array.
This way it's very explicit about what properties you are displaying.
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="item in details">
{{ [ item.address0, item.address1, item.address2, item.address3] | removeEmpties | joinBy:', ' }}
</li>
</ul>
</body>
With the following filters:
app.filter('removeEmpties', function () {
return function (input,delimiter) {
return (input || []).filter(function (i) { return !!i; });
};
});
app.filter('joinBy', function () {
return function (input,delimiter) {
return (input || []).join(delimiter || ',');
};
});
Here's the updated Plunkr
Tricky but should work in your case Also no filter need
{{ item.address0 }} <span ng-if="item.address1">,
</span> {{ item.address1}}<span ng-if="item.address2">,</span>{{
item.address2}}
<span ng-if="item.address3">,</span>{{ item.address3}}
Here is working example
I would prefer writing a function instead of adding a filter so many times.
$scope.mergeAddresses = function(item) {
var address = item.address0;
[1,2,3].forEach(function(i) {
var add = item["address"+i];
if (!add) return;
address += (address ? ", " : "") + add;
});
if (address) address += ".";
return address;
}
Plunker

Edit an object inside several ng-repeat

I got two ng-repeat who display objects call 'post', and I have a button for edit the text and update it.
Everything works fine but I still got a little problem here's the html code :
<li ng-repeat="post in posts | filter: { etat: 'aTraiter' } ">
<p ng-show="!editing[$index]" ng-model href="#/{{post._id}}">{{ post.corps }}</p>
<input ng-show="editing[$index]" type="text" ng-model="post.corps">
<a ng-show="!editing[$index" ng-click="edit(post)">Editer</a>
<a ng-show="editing[$index]" ng-click="update(post)">Confirmer</a>
<a ng-show="editing[$index]" ng-click="cancel(post)">Annuler</a>
</li>
<li ng-repeat="post in posts | filter: { etat: 'enCours' } ">
<p ng-show="!editing[$index]" ng-model href="#/{{post._id}}">{{ post.corps }}</p>
<input ng-show="editing[$index]" type="text" ng-model="post.corps">
<a ng-show="!editing[$index]" ng-click="edit(post)">Editer</a>
<a ng-show="editing[$index]" ng-click="update(post)">Confirmer</a>
<a ng-show="editing[$index]" ng-click="cancel(post)">Annuler</a>
</li>
the controller :
$scope.editing = [];
$scope.posts= Posts.query();
$scope.edit = function(post){
var idx = $scope.posts.indexOf(post);
$scope.editing[idx] = angular.copy($scope.posts[idx]);
}
$scope.update = function(post){
var idx = $scope.posts.indexOf(post);
Posts.update({id: post._id}, post);
$scope.editing[idx] = false;
}
$scope.cancel = function(post){
var idx = $scope.posts.indexOf(post);
post = angular.copy(post);
$scope.editing[idx] = false;
}
If I got just one post I can edit it and all is ok.
But when I got one post in the both ng-repeat I got some bugs, if I click on edit, buttons change in the both ng-repeat and the both post can be edit.
I'm not really sure but I thinks it's a problem with my :
ng-show="editing[$index]"
I try to put the index of the post like this
ng-show="editing[posts.indexOf(post)]"
But this is not working, can somebody help me ?
(The jsfiddle link)
EDIT the post query :
Posts.query();: Array[0]
0: d
__v: 0
_id: "569563a96a81e64409623179"
corps: "asdad"
etat: "enCours"
nomReseau: "Google+"
section: "evolution"
__proto__: d
1: d
__v: 0
_id: "56954e676a81e6440962316b"
corps: "sdfsdfsf"
etat: "enCours"
nomReseau: "Google+"
section: "evolution"
__proto__: d
Using $index in a filtered repeat to access information in your array.
The problem with using $index, passing it to your controller and then trying to use that index to search for a 'post' in your array of posts, is that $index references your view index and not the true index of the item in the array.
This is traditionally not a problem unless you are filtering your array with ng-repeat. Why? Because $index does not reflex the index of the item, but the index of how the item is appearing in the DOM. So although the first rendered post could have index 5 in your posts array, it will still have $index of 0 because it is the first rendered item in the ng-repeat.
Solution: Separate your data first into two separate arrays and then repeat through them individually.
Controller:
$scope.posts = Posts.query();
$scope.postsATraiter = $scope.posts.filter(function(item, index) {
return item.etat === 'aTraiter';
});
$scope.postsEnCours = $scope.posts.filter(function(item, index) {
return item.etat === 'enCours';
})
$scope.edit = function(post, postType){
var idx = getPostsByType(postType).indexOf(post);
$scope.editing[idx] = angular.copy($scope.posts[idx]);
}
$scope.update = function(post, postType){
var idx = getPostsByType(postType).indexOf(post);
Posts.update({id: post._id}, post);
$scope.editing[idx] = false;
}
$scope.cancel = function(post, postType){
var idx = getPostsByType(postType).indexOf(post);
post = angular.copy(post);
$scope.editing[idx] = false;
}
function getPostsByType(postTypeString) {
if (postTypeString === 'aTraiter') {
return $scope.postsATraiter;
} else {
return $scope.postsEnCours;
}
}
Now that the data is separate you are free to use $index because we know that the $index will respect the true index of the item in the array because it is not being filtered.
<li ng-repeat="post in postsATraiter">
<p ng-show="!editing[$index]" ng-model href="#/{{post._id}}">{{ post.corps }}</p>
<input ng-show="editing[$index]" type="text" ng-model="post.corps">
<a ng-show="!editing[$index" ng-click="edit(post, 'aTraiter')">Editer</a>
<a ng-show="editing[$index]" ng-click="update(post, 'aTraiter')">Confirmer</a>
<a ng-show="editing[$index]" ng-click="cancel(post,'aTraiter')">Annuler</a>
</li>
<li ng-repeat="post in postsEnCours">
<p ng-show="!editing[$index]" ng-model href="#/{{post._id}}">{{ post.corps }}</p>
<input ng-show="editing[$index]" type="text" ng-model="post.corps">
<a ng-show="!editing[$index]" ng-click="edit(post, 'enCours')">Editer</a>
<a ng-show="editing[$index]" ng-click="update(post, 'enCours')">Confirmer</a>
<a ng-show="editing[$index]" ng-click="cancel(post, 'enCours')">Annuler</a>
</li>
You may have to fiddle around with your implementation more, but it appears that $index and the way it is being used may be the root of the problems you are having.
You're using $index, which is just ... well... an index. Both collections can have a value at index==1, right? So, $index isn't unique across the entire set of posts.
Luckily, it would appear that you have an ID for each post that seems to be unique: post._id. How about using that instead?
One little side-note - I'm using jquery's grep method below to find a post by Id. It's fine, but I like underscore.js better. Take a look at both ...
So, here's your controller code:
//This is me willfully and wantonly changing your variables ... sorry.
$scope.selectedPost = undefined;
$scope.selectedPost_unchanged = undefined;
//This is the same, though, so you should feel good ;-)
$scope.posts= Posts.query();
$scope.edit = function(postId){
var result = $.grep($scope.posts, function(p){ return p._id == postId; });
if(result.length==0) { return; }
//just store the one we are editing. that should be cool, right?
$scope.selectedPost = results[0];
//ok... im changing this too... see if you like it better?
//we're gonna use it in the CANCEL method (below).
$scope.selectedPost_unchanged = angular.copy(results[0]);
}
$scope.update = function(post){
Posts.update({id: post._id}, post);
$scope.selectedPost = undefined;
$scope.selectedPost_unchanged = undefined;
}
$scope.cancel = function(post){
post = angular.extend({}, $scope.selectedPost_unchanged);
$scope.selectedPost = undefined;
$scope.selectedPost_unchanged = undefined;
}
//This is new too ... just adding it so that the html is clearer.
$scope.isEditing = function(post) {
if($scope.selectedPost==undefined) { return false; }
return post._id == $scope.selectedPost._id;
}
The HTML changes a bit too
All of your editing[$index] code becomes just isEditing(post)
VoilĂ ! Except maybe use css+ng-class...
Not for nothing, but I would add the while editing/not-editing show/hide using css. Then, add an ng-class to the li element instead (eg - ng-class="{editing: isEditing(post)}"). Then, take care of all your show/hides with css. This way, you only have to put isEditing(post) in ONE location in your html (instead of adding it to every element). ng tags are not expensive, but they REALLY add up inside of ng-repeat tags.

AngularJS Dynamically Update ng-style

I'm trying to set an initial background color on a set of div's that are created using ng-repeat. I also want to update the background color for each div on hover.
I'm able to see the correct color on hover, but I'm not sure how I can set the initial background color for each div when I have a variable in the ng-style. I did try looping through the projects in the controller and calling the rgba function in my controller, but it just applies that last background color to all of the divs.
Here is my ng-repeat block:
<section ng-controller="ProjectsCtrl" class="work">
<div ng-repeat="project in projects" class="work-example" ng-style="{'background-color': '{{ project.background_color }}'}">
<a href="#">
<div class="inner" ng-style="{'background-image': 'url({{ project.image_url }})'}">
<div class="type">{{ project.title }}</div>
<div class="client">{{ project.client }}</div>
<div class="overlay" ng-style="background" ng-mouseover="rgba(project.background_color, 0.2)"></div>
</div>
</a>
</div>
</section>
My controller has a function called rgba that will take the hex (coming from rails api call) and turn it into rgba.
App.controller('ProjectsCtrl', ['$scope', 'Projects', function($scope, Projects) {
$scope.rgba = function(hex, opacity) {
var hex = hex.replace('#', ''),
r = parseInt(hex.substring(0,2), 16),
g = parseInt(hex.substring(2,4), 16),
b = parseInt(hex.substring(4,6), 16),
result = 'rgba('+ r + ',' + g + ',' + b + ',' + opacity + ')';
$scope.background = { 'background-color': result }
}
$scope.projects = Projects.query();
}
]);
Here is the service my controller is calling:
App.factory('Projects', ['$resource', function($resource) {
return $resource('/api/projects/:id', {
id: '#id'
});
}
]);
Here is my attempt to update ng-style from the controller (but assigns all divs the last background color):
$scope.projects = Projects.query(function(projects){
angular.forEach(projects, function(value, index) {
$scope.rgba(value.background_color, '0.8');
});
});
I'm pretty new to the AngularJS world, so I hope all of this makes sense. Any help is greatly appreciated. Thanks!
The reason why "it applies that last background color to all of the divs" is because, of the following code.
$scope.rgba = function(hex, opacity) {
var hex = hex.replace('#', ''),
r = parseInt(hex.substring(0,2), 16),
g = parseInt(hex.substring(2,4), 16),
b = parseInt(hex.substring(4,6), 16),
result = 'rgba('+ r + ',' + g + ',' + b + ',' + opacity + ')';
$scope.background = { 'background-color': result }
}
$scope.projects = Projects.query(function(projects){
angular.forEach(projects, function(value, index) {
$scope.rgba(value.background_color, '0.8');
});
});
When your angular.forEach runs, it is invoking $scope.rgba which is in turn updating the value of $scope.background to the latest background color. Inside your HTML markup, you have <div class="overlay" ng-style="background" ng-mouseover="rgba(project.background_color, 0.2)"></div> which looks for a variable called background in $scope.
Now the catch here is, as this markup is inside an ng-repeat every single repetition of the markup will have the same value for ng-style as everything is looking at the same object $scope.background.
Instead, what I would suggest you to do is the following.
Projects.query(function (projects) {
$scope.projects = projects; // <- $scope.projects is set when the query completes
angular.forEach(projects, function (value, index) {
$scope.rgba(project, '0.8');
});
});
$scope.rgba = function(project, opacity) {
var hex = project.background_color.replace('#', ''),
r = parseInt(hex.substring(0,2), 16),
g = parseInt(hex.substring(2,4), 16),
b = parseInt(hex.substring(4,6), 16),
result = 'rgba('+ r + ',' + g + ',' + b + ',' + opacity + ')';
project.backgroundStyle = { 'background-color': result }
}
And then your markup:
<section ng-controller="ProjectsCtrl" class="work">
<div ng-repeat="project in projects" class="work-example" ng-style="{'background-color': '{{ project.background_color }}'}">
<a href="#">
<div class="inner" ng-style="{'background-image': 'url({{ project.image_url }})'}">
<div class="type">{{ project.title }}</div>
<div class="client">{{ project.client }}</div>
<div class="overlay" ng-style="project.backgroundStyle" ng-mouseover="rgba(project.background_color, 0.2)"></div>
</div>
</a>
</div>
</section>
I believe this would solve your issue of every div having the latest background.
$resource.query returns a wrapper object containing a promise instead of the actual results of the query.
So with the following code:
$scope.projects = Projects.query(function(projects){
angular.forEach(projects, function(value, index) {
$scope.rgba(value.background_color, '0.8');
});
})
You are actually setting $scope.projects to the promise wrapper.
You need to change it to something like this:
Projects.query(function (projects) {
$scope.projects = projects; // <- $scope.projects is set when the query completes
angular.forEach(projects, function (value, index) {
$scope.rgba(value.background_color, '0.8');
});
});

Angular ng-repeat with a specific value [duplicate]

Angular does provide some support for a for loop using numbers within its HTML directives:
<div data-ng-repeat="i in [1,2,3,4,5]">
do something
</div>
But if your scope variable includes a range that has a dynamic number then you will need to create an empty array each time.
In the controller
var range = [];
for(var i=0;i<total;i++) {
range.push(i);
}
$scope.range = range;
In the HTML
<div data-ng-repeat="i in range">
do something
</div>
This works, but it is unnecessary since we won't be using the range array at all within the loop. Does anyone know of setting a range or a regular for min/max value?
Something like:
<div data-ng-repeat="i in 1 .. 100">
do something
</div>
I tweaked this answer a bit and came up with this fiddle.
Filter defined as:
var myApp = angular.module('myApp', []);
myApp.filter('range', function() {
return function(input, total) {
total = parseInt(total);
for (var i=0; i<total; i++) {
input.push(i);
}
return input;
};
});
With the repeat used like this:
<div ng-repeat="n in [] | range:100">
do something
</div>
I came up with an even simpler version, for creating a range between two defined numbers, eg. 5 to 15
See demo on JSFiddle
HTML:
<ul>
<li ng-repeat="n in range(5,15)">Number {{n}}</li>
</ul>
Controller:
$scope.range = function(min, max, step) {
step = step || 1;
var input = [];
for (var i = min; i <= max; i += step) {
input.push(i);
}
return input;
};
Nothing but plain Javascript (you don't even need a controller):
<div ng-repeat="n in [].constructor(10) track by $index">
{{ $index }}
</div>
Very useful when mockuping
I came up with a slightly different syntax which suits me a little bit more and adds an optional lower bound as well:
myApp.filter('makeRange', function() {
return function(input) {
var lowBound, highBound;
switch (input.length) {
case 1:
lowBound = 0;
highBound = parseInt(input[0]) - 1;
break;
case 2:
lowBound = parseInt(input[0]);
highBound = parseInt(input[1]);
break;
default:
return input;
}
var result = [];
for (var i = lowBound; i <= highBound; i++)
result.push(i);
return result;
};
});
which you can use as
<div ng-repeat="n in [10] | makeRange">Do something 0..9: {{n}}</div>
or
<div ng-repeat="n in [20, 29] | makeRange">Do something 20..29: {{n}}</div>
For those new to angularjs.
The index can be gotten by using $index.
For example:
<div ng-repeat="n in [] | range:10">
do something number {{$index}}
</div>
Which will, when you're using Gloopy's handy filter, print:
do something number 0
do something number 1
do something number 2
do something number 3
do something number 4
do something number 5
do something number 6
do something number 7
do something number 8
do something number 9
A short way of doing this would be to use Underscore.js's _.range() method. :)
http://underscorejs.org/#range
// declare in your controller or wrap _.range in a function that returns a dynamic range.
var range = _.range(1, 11);
// val will be each number in the array not the index.
<div ng-repeat='val in range'>
{{ $index }}: {{ val }}
</div>
I use my custom ng-repeat-range directive:
/**
* Ng-Repeat implementation working with number ranges.
*
* #author Umed Khudoiberdiev
*/
angular.module('commonsMain').directive('ngRepeatRange', ['$compile', function ($compile) {
return {
replace: true,
scope: { from: '=', to: '=', step: '=' },
link: function (scope, element, attrs) {
// returns an array with the range of numbers
// you can use _.range instead if you use underscore
function range(from, to, step) {
var array = [];
while (from + step <= to)
array[array.length] = from += step;
return array;
}
// prepare range options
var from = scope.from || 0;
var step = scope.step || 1;
var to = scope.to || attrs.ngRepeatRange;
// get range of numbers, convert to the string and add ng-repeat
var rangeString = range(from, to + 1, step).join(',');
angular.element(element).attr('ng-repeat', 'n in [' + rangeString + ']');
angular.element(element).removeAttr('ng-repeat-range');
$compile(element)(scope);
}
};
}]);
and html code is
<div ng-repeat-range from="0" to="20" step="5">
Hello 4 times!
</div>
or simply
<div ng-repeat-range from="5" to="10">
Hello 5 times!
</div>
or even simply
<div ng-repeat-range to="3">
Hello 3 times!
</div>
or just
<div ng-repeat-range="7">
Hello 7 times!
</div>
Simplest no code solution was to init an array with the range, and use the $index + however much I want to offset by:
<select ng-init="(_Array = []).length = 5;">
<option ng-repeat="i in _Array track by $index">{{$index+5}}</option>
</select>
Without any change in your controller, you can use this:
ng-repeat="_ in ((_ = []) && (_.length=51) && _) track by $index"
Enjoy!
Method definition
The code below defines a method range() available to the entire scope of your application MyApp. Its behaviour is very similar to the Python range() method.
angular.module('MyApp').run(['$rootScope', function($rootScope) {
$rootScope.range = function(min, max, step) {
// parameters validation for method overloading
if (max == undefined) {
max = min;
min = 0;
}
step = Math.abs(step) || 1;
if (min > max) {
step = -step;
}
// building the array
var output = [];
for (var value=min; value<max; value+=step) {
output.push(value);
}
// returning the generated array
return output;
};
}]);
Usage
With one parameter:
<span ng-repeat="i in range(3)">{{ i }}, </span>
0, 1, 2,
With two parameters:
<span ng-repeat="i in range(1, 5)">{{ i }}, </span>
1, 2, 3, 4,
With three parameters:
<span ng-repeat="i in range(-2, .7, .5)">{{ i }}, </span>
-2, -1.5, -1, -0.5, 0, 0.5,
You can use 'after' or 'before' filters in angular.filter module (https://github.com/a8m/angular-filter)
$scope.list = [1,2,3,4,5,6,7,8,9,10]
HTML:
<li ng-repeat="i in list | after:4">
{{ i }}
</li>
result:
5, 6, 7, 8, 9, 10
Shortest answer: 2 lines of code
JS (in your AngularJS controller)
$scope.range = new Array(MAX_REPEATS); // MAX_REPEATS should be the most repetitions you will ever need in a single ng-repeat
HTML
<div data-ng-repeat="i in range.slice(0,myCount) track by $index"></div>
...where myCount is the number of stars that should appear in this location.
You can use $index for any tracking operations. E.g. if you want to print some mutation on the index, you might put the following in the div:
{{ ($index + 1) * 0.5 }}
Hi you can achieve this using pure html using AngularJS (NO Directive is required!)
<div ng-app="myapp" ng-controller="YourCtrl" ng-init="x=[5];">
<div ng-if="i>0" ng-repeat="i in x">
<!-- this content will repeat for 5 times. -->
<table class="table table-striped">
<tr ng-repeat="person in people">
<td>{{ person.first + ' ' + person.last }}</td>
</tr>
</table>
<p ng-init="x.push(i-1)"></p>
</div>
</div>
Using UnderscoreJS:
angular.module('myModule')
.run(['$rootScope', function($rootScope) { $rootScope.range = _.range; }]);
Applying this to $rootScope makes it available everywhere:
<div ng-repeat="x in range(1,10)">
{{x}}
</div>
Very simple one:
$scope.totalPages = new Array(10);
<div id="pagination">
<a ng-repeat="i in totalPages track by $index">
{{$index+1}}
</a>
</div>
Set Scope in controller
var range = [];
for(var i=20;i<=70;i++) {
range.push(i);
}
$scope.driverAges = range;
Set Repeat in Html Template File
<select type="text" class="form-control" name="driver_age" id="driver_age">
<option ng-repeat="age in driverAges" value="{{age}}">{{age}}</option>
</select>
An improvement to #Mormegil's solution
app.filter('makeRange', function() {
return function(inp) {
var range = [+inp[1] && +inp[0] || 0, +inp[1] || +inp[0]];
var min = Math.min(range[0], range[1]);
var max = Math.max(range[0], range[1]);
var result = [];
for (var i = min; i <= max; i++) result.push(i);
if (range[0] > range[1]) result.reverse();
return result;
};
});
usage
<span ng-repeat="n in [3, -3] | makeRange" ng-bind="n"></span>
3 2 1 0 -1 -2 -3
<span ng-repeat="n in [-3, 3] | makeRange" ng-bind="n"></span>
-3 -2 -1 0 1 2 3
<span ng-repeat="n in [3] | makeRange" ng-bind="n"></span>
0 1 2 3
<span ng-repeat="n in [-3] | makeRange" ng-bind="n"></span>
0 -1 -2 -3
I tried the following and it worked just fine for me:
<md-radio-button ng-repeat="position in formInput.arrayOfChoices.slice(0,6)" value="{{position}}">{{position}}</md-radio-button>
Angular 1.3.6
Late to the party. But i ended up just doing this:
In your controller:
$scope.repeater = function (range) {
var arr = [];
for (var i = 0; i < range; i++) {
arr.push(i);
}
return arr;
}
Html:
<select ng-model="myRange">
<option>3</option>
<option>5</option>
</select>
<div ng-repeat="i in repeater(myRange)"></div>
This is jzm's improved answer (i cannot comment else i would comment her/his answer because s/he included errors).
The function has a start/end range value, so it's more flexible, and... it works. This particular case is for day of month:
$scope.rangeCreator = function (minVal, maxVal) {
var arr = [];
for (var i = minVal; i <= maxVal; i++) {
arr.push(i);
}
return arr;
};
<div class="col-sm-1">
<select ng-model="monthDays">
<option ng-repeat="day in rangeCreator(1,31)">{{day}}</option>
</select>
</div>
<div ng-init="avatars = [{id : 0}]; flag = true ">
<div ng-repeat='data in avatars' ng-if="avatars.length < 10 || flag"
ng-init="avatars.length != 10 ? avatars.push({id : $index+1}) : ''; flag = avatars.length <= 10 ? true : false">
<img ng-src="http://actual-names.com/wp-content/uploads/2016/01/sanskrit-baby-girl-names-400x275.jpg">
</div>
</div>
If you want to achieve this in html without any controller or factory.
I whipped this up and saw it might be useful for some. (Yes, CoffeeScript. Sue me.)
Directive
app.directive 'times', ->
link: (scope, element, attrs) ->
repeater = element.html()
scope.$watch attrs.times, (value) ->
element.html ''
return unless value?
element.html Array(value + 1).join(repeater)
To use:
HTML
<div times="customer.conversations_count">
<i class="icon-picture></i>
</div>
Can this get any simpler?
I'm wary about filters because Angular likes to re-evaluate them for no good reason all the time, and it's a huge bottleneck if you have thousands of them like I do.
This directive will even watch for changes in your model, and update the element accordingly.
Suppose $scope.refernceurl is an array then
for(var i=0; i<$scope.refernceurl.length; i++){
$scope.urls+=$scope.refernceurl[i].link+",";
}
This is the simplest variant:
just use array of integers....
<li ng-repeat="n in [1,2,3,4,5]">test {{n}}</li>

AngularJS For Loop with Numbers & Ranges

Angular does provide some support for a for loop using numbers within its HTML directives:
<div data-ng-repeat="i in [1,2,3,4,5]">
do something
</div>
But if your scope variable includes a range that has a dynamic number then you will need to create an empty array each time.
In the controller
var range = [];
for(var i=0;i<total;i++) {
range.push(i);
}
$scope.range = range;
In the HTML
<div data-ng-repeat="i in range">
do something
</div>
This works, but it is unnecessary since we won't be using the range array at all within the loop. Does anyone know of setting a range or a regular for min/max value?
Something like:
<div data-ng-repeat="i in 1 .. 100">
do something
</div>
I tweaked this answer a bit and came up with this fiddle.
Filter defined as:
var myApp = angular.module('myApp', []);
myApp.filter('range', function() {
return function(input, total) {
total = parseInt(total);
for (var i=0; i<total; i++) {
input.push(i);
}
return input;
};
});
With the repeat used like this:
<div ng-repeat="n in [] | range:100">
do something
</div>
I came up with an even simpler version, for creating a range between two defined numbers, eg. 5 to 15
See demo on JSFiddle
HTML:
<ul>
<li ng-repeat="n in range(5,15)">Number {{n}}</li>
</ul>
Controller:
$scope.range = function(min, max, step) {
step = step || 1;
var input = [];
for (var i = min; i <= max; i += step) {
input.push(i);
}
return input;
};
Nothing but plain Javascript (you don't even need a controller):
<div ng-repeat="n in [].constructor(10) track by $index">
{{ $index }}
</div>
Very useful when mockuping
I came up with a slightly different syntax which suits me a little bit more and adds an optional lower bound as well:
myApp.filter('makeRange', function() {
return function(input) {
var lowBound, highBound;
switch (input.length) {
case 1:
lowBound = 0;
highBound = parseInt(input[0]) - 1;
break;
case 2:
lowBound = parseInt(input[0]);
highBound = parseInt(input[1]);
break;
default:
return input;
}
var result = [];
for (var i = lowBound; i <= highBound; i++)
result.push(i);
return result;
};
});
which you can use as
<div ng-repeat="n in [10] | makeRange">Do something 0..9: {{n}}</div>
or
<div ng-repeat="n in [20, 29] | makeRange">Do something 20..29: {{n}}</div>
For those new to angularjs.
The index can be gotten by using $index.
For example:
<div ng-repeat="n in [] | range:10">
do something number {{$index}}
</div>
Which will, when you're using Gloopy's handy filter, print:
do something number 0
do something number 1
do something number 2
do something number 3
do something number 4
do something number 5
do something number 6
do something number 7
do something number 8
do something number 9
A short way of doing this would be to use Underscore.js's _.range() method. :)
http://underscorejs.org/#range
// declare in your controller or wrap _.range in a function that returns a dynamic range.
var range = _.range(1, 11);
// val will be each number in the array not the index.
<div ng-repeat='val in range'>
{{ $index }}: {{ val }}
</div>
I use my custom ng-repeat-range directive:
/**
* Ng-Repeat implementation working with number ranges.
*
* #author Umed Khudoiberdiev
*/
angular.module('commonsMain').directive('ngRepeatRange', ['$compile', function ($compile) {
return {
replace: true,
scope: { from: '=', to: '=', step: '=' },
link: function (scope, element, attrs) {
// returns an array with the range of numbers
// you can use _.range instead if you use underscore
function range(from, to, step) {
var array = [];
while (from + step <= to)
array[array.length] = from += step;
return array;
}
// prepare range options
var from = scope.from || 0;
var step = scope.step || 1;
var to = scope.to || attrs.ngRepeatRange;
// get range of numbers, convert to the string and add ng-repeat
var rangeString = range(from, to + 1, step).join(',');
angular.element(element).attr('ng-repeat', 'n in [' + rangeString + ']');
angular.element(element).removeAttr('ng-repeat-range');
$compile(element)(scope);
}
};
}]);
and html code is
<div ng-repeat-range from="0" to="20" step="5">
Hello 4 times!
</div>
or simply
<div ng-repeat-range from="5" to="10">
Hello 5 times!
</div>
or even simply
<div ng-repeat-range to="3">
Hello 3 times!
</div>
or just
<div ng-repeat-range="7">
Hello 7 times!
</div>
Simplest no code solution was to init an array with the range, and use the $index + however much I want to offset by:
<select ng-init="(_Array = []).length = 5;">
<option ng-repeat="i in _Array track by $index">{{$index+5}}</option>
</select>
Without any change in your controller, you can use this:
ng-repeat="_ in ((_ = []) && (_.length=51) && _) track by $index"
Enjoy!
Method definition
The code below defines a method range() available to the entire scope of your application MyApp. Its behaviour is very similar to the Python range() method.
angular.module('MyApp').run(['$rootScope', function($rootScope) {
$rootScope.range = function(min, max, step) {
// parameters validation for method overloading
if (max == undefined) {
max = min;
min = 0;
}
step = Math.abs(step) || 1;
if (min > max) {
step = -step;
}
// building the array
var output = [];
for (var value=min; value<max; value+=step) {
output.push(value);
}
// returning the generated array
return output;
};
}]);
Usage
With one parameter:
<span ng-repeat="i in range(3)">{{ i }}, </span>
0, 1, 2,
With two parameters:
<span ng-repeat="i in range(1, 5)">{{ i }}, </span>
1, 2, 3, 4,
With three parameters:
<span ng-repeat="i in range(-2, .7, .5)">{{ i }}, </span>
-2, -1.5, -1, -0.5, 0, 0.5,
You can use 'after' or 'before' filters in angular.filter module (https://github.com/a8m/angular-filter)
$scope.list = [1,2,3,4,5,6,7,8,9,10]
HTML:
<li ng-repeat="i in list | after:4">
{{ i }}
</li>
result:
5, 6, 7, 8, 9, 10
Shortest answer: 2 lines of code
JS (in your AngularJS controller)
$scope.range = new Array(MAX_REPEATS); // MAX_REPEATS should be the most repetitions you will ever need in a single ng-repeat
HTML
<div data-ng-repeat="i in range.slice(0,myCount) track by $index"></div>
...where myCount is the number of stars that should appear in this location.
You can use $index for any tracking operations. E.g. if you want to print some mutation on the index, you might put the following in the div:
{{ ($index + 1) * 0.5 }}
Hi you can achieve this using pure html using AngularJS (NO Directive is required!)
<div ng-app="myapp" ng-controller="YourCtrl" ng-init="x=[5];">
<div ng-if="i>0" ng-repeat="i in x">
<!-- this content will repeat for 5 times. -->
<table class="table table-striped">
<tr ng-repeat="person in people">
<td>{{ person.first + ' ' + person.last }}</td>
</tr>
</table>
<p ng-init="x.push(i-1)"></p>
</div>
</div>
Using UnderscoreJS:
angular.module('myModule')
.run(['$rootScope', function($rootScope) { $rootScope.range = _.range; }]);
Applying this to $rootScope makes it available everywhere:
<div ng-repeat="x in range(1,10)">
{{x}}
</div>
Very simple one:
$scope.totalPages = new Array(10);
<div id="pagination">
<a ng-repeat="i in totalPages track by $index">
{{$index+1}}
</a>
</div>
Set Scope in controller
var range = [];
for(var i=20;i<=70;i++) {
range.push(i);
}
$scope.driverAges = range;
Set Repeat in Html Template File
<select type="text" class="form-control" name="driver_age" id="driver_age">
<option ng-repeat="age in driverAges" value="{{age}}">{{age}}</option>
</select>
An improvement to #Mormegil's solution
app.filter('makeRange', function() {
return function(inp) {
var range = [+inp[1] && +inp[0] || 0, +inp[1] || +inp[0]];
var min = Math.min(range[0], range[1]);
var max = Math.max(range[0], range[1]);
var result = [];
for (var i = min; i <= max; i++) result.push(i);
if (range[0] > range[1]) result.reverse();
return result;
};
});
usage
<span ng-repeat="n in [3, -3] | makeRange" ng-bind="n"></span>
3 2 1 0 -1 -2 -3
<span ng-repeat="n in [-3, 3] | makeRange" ng-bind="n"></span>
-3 -2 -1 0 1 2 3
<span ng-repeat="n in [3] | makeRange" ng-bind="n"></span>
0 1 2 3
<span ng-repeat="n in [-3] | makeRange" ng-bind="n"></span>
0 -1 -2 -3
I tried the following and it worked just fine for me:
<md-radio-button ng-repeat="position in formInput.arrayOfChoices.slice(0,6)" value="{{position}}">{{position}}</md-radio-button>
Angular 1.3.6
Late to the party. But i ended up just doing this:
In your controller:
$scope.repeater = function (range) {
var arr = [];
for (var i = 0; i < range; i++) {
arr.push(i);
}
return arr;
}
Html:
<select ng-model="myRange">
<option>3</option>
<option>5</option>
</select>
<div ng-repeat="i in repeater(myRange)"></div>
This is jzm's improved answer (i cannot comment else i would comment her/his answer because s/he included errors).
The function has a start/end range value, so it's more flexible, and... it works. This particular case is for day of month:
$scope.rangeCreator = function (minVal, maxVal) {
var arr = [];
for (var i = minVal; i <= maxVal; i++) {
arr.push(i);
}
return arr;
};
<div class="col-sm-1">
<select ng-model="monthDays">
<option ng-repeat="day in rangeCreator(1,31)">{{day}}</option>
</select>
</div>
<div ng-init="avatars = [{id : 0}]; flag = true ">
<div ng-repeat='data in avatars' ng-if="avatars.length < 10 || flag"
ng-init="avatars.length != 10 ? avatars.push({id : $index+1}) : ''; flag = avatars.length <= 10 ? true : false">
<img ng-src="http://actual-names.com/wp-content/uploads/2016/01/sanskrit-baby-girl-names-400x275.jpg">
</div>
</div>
If you want to achieve this in html without any controller or factory.
I whipped this up and saw it might be useful for some. (Yes, CoffeeScript. Sue me.)
Directive
app.directive 'times', ->
link: (scope, element, attrs) ->
repeater = element.html()
scope.$watch attrs.times, (value) ->
element.html ''
return unless value?
element.html Array(value + 1).join(repeater)
To use:
HTML
<div times="customer.conversations_count">
<i class="icon-picture></i>
</div>
Can this get any simpler?
I'm wary about filters because Angular likes to re-evaluate them for no good reason all the time, and it's a huge bottleneck if you have thousands of them like I do.
This directive will even watch for changes in your model, and update the element accordingly.
Suppose $scope.refernceurl is an array then
for(var i=0; i<$scope.refernceurl.length; i++){
$scope.urls+=$scope.refernceurl[i].link+",";
}
This is the simplest variant:
just use array of integers....
<li ng-repeat="n in [1,2,3,4,5]">test {{n}}</li>

Resources