How to solve the error: [$rootScope:infdig]? - angularjs

When I am using ng-repeats in ul's and li's I am getting the errors.
Here is my html code:
<ul>
<li ng-repeat="(key, value) in (myData | groupBy: 'id')">
{{key}}
<ul>
<li ng-repeat="details in value">
{{details.name}}
</li>
</ul>
</li>
</ul>
JS code:
.filter('groupBy', function () {
return function (data, key) {
var result = {};
for (var i = 0; i < data.length; i++) {
if (!result[data[i][key]])
result[data[i][key]] = [];
result[data[i][key]].push(data[i])
}
alert(JSON.stringify(result));
return result;
};
});
These are the errors I am getting

Try to put track by $index in the ng-repeat like this:
<ul>
<li ng-repeat="(key, value) in myData track by id">
{{key}}
<ul>
<li ng-repeat="details in value">
{{details.name}}
</li>
</ul>
</li>
</ul>
You can also track by $index if you have duplicates in array
<li ng-repeat="(key, value) in myData track by $index">

The infinite digest is caused by the filter that returns a new result every time it runs through the function. You'll have to rewrite the function so that it directly modifies the original data argument and you return the data argument again.

Related

AngularJS - Custom filter not working

I want to find the names, starting with the given letter i.e 'm' using angular's custom filter. Here I should get 2 entries in solutions but my view part shows only two bullets of an unordered list and not showing the names that starts with 'm'.
This is my filter:
arg.filter("startwith",function()
{
return function(input,option)
{
var op = [];//var s="";
for(var i=0;i<input.length;i++)
{
if(input[i].sname.charAt(0) == option)
op.push(input[i].sname);
}
// $scope.op;
// s=op.toString();
return op;
}
});
This is controller:
$scope.stud = [
{sid:1,sname:'john',gender:1,type:"fulltime"},
{sid:2,sname:'ashish',gender:1,type:"fulltime"},
{sid:3,sname:'naina',gender:2,type:"parttime"},
{sid:4,sname:'mitesh',gender:3,type:"fulltime"},
{sid:5,sname:'mithila',gender:2,type:"parttime"}
]
This is the view:
<h3> Names Start with M</h3>
<ul>
<li ng-repeat="s in stud | startwith : 'm'">
{{stud.sname}}
</li>
</ul>
It is because in your custom filter you are not returning objects but returning strings therefore the following would return empty as your strings would not have property of sname
<ul>
<li ng-repeat="s in stud | startwith : 'm'">
{{s.sname}}
</li>
</ul>
changing {{s.sname}} line to {{s}} would give you results.
<ul>
<li ng-repeat="s in stud | startwith : 'm'">
{{s}}
</li>
</ul>
Demo

Grabbing value from nested json array with Angular

I'm having trouble accessing the artists array within the items array here to be able to render the name field:
I'm currently able to grab other values at the same level as the artists that are simple objects. How can I loop through the array of the nested array?
Controller
$scope.search = "";
$scope.listLimit = "10";
$scope.selectedSongs = [];
$scope.addItem = function(song){
$scope.selectedSongs.push(song);
}
function fetch() {
$http.get("https://api.spotify.com/v1/search?q=" + $scope.search + "&type=track&limit=50")
.then(function(response) {
console.log(response.data.tracks.items);
$scope.isTheDataLoaded = true;
$scope.details = response.data.tracks.items;
});
}
Template
<div class="col-md-4">
<div class="playlist">
<h3>Top 10 Playlist</h3>
<ul class="songs" ng-repeat="song in selectedSongs track by $index | limitTo: listLimit">
<li><b>{{song.name}}</b></li>
<li>{{song.artists.name}}</li>
<li contenteditable='true'>Click to add note</li>
<li contenteditable='true'>Click to add url for image</li>
</ul>
<div id="result"></div>
</div>
</div>
You should do another ng-repeat to access the artists,
<div class="songs" ng-repeat="song in selectedSongs track by $index | limitTo: listLimit">
<ul ng-repeat="artist in song.artists">
<li><b>{{song.name}}</b></li>
<li>{{artist.name}}</li>
<li contenteditable='true'>Click to add note</li>
<li contenteditable='true'>Click to add url for image</li>
</ul>
</div>

iteration scope name in ng-repeat

This is my controller
var i;
for (i = 1; i <= 3; i++ ) {
$scope["items"+i].push({
notification: item.notification,
admin_id: item.admin_id,
user_id: item.user_id,
chat_time: item.chat_time
})
}
This is my static scope in ng-repeat
<ul>
<li ng-repeat="x in items1"></li>
<li ng-repeat="x in items2"></li>
<li ng-repeat="x in items3"></li>
</ul>
How to make dynamic iteration scope variabel in ng-repeat in single ng-repeat like this
<ul>
<li ng-repeat="x in items[i++]">
<!-- generate from here-->
<li ng-repeat="x in items1"></li>
<li ng-repeat="x in items2"></li>
<li ng-repeat="x in items3"></li>
<!-- to here -->
</li>
</ul>
and it will display like my static scope
Thanks , appreciate ur help and comment
You need to store all the different arrays in a new Array and then, you can loop it around as shown (I have created a sample):
JS:
$scope.item1 = [ /* json array 1 */];
$scope.item2 = [ /* json array 2 */];
$scope.item3 = [ /* json array 3 */];
$scope.itemsList = [];
for (i = 0; i < 3; i++) {
var varName = '$scope.item' + (i + 1);
$scope.itemsList.push(eval(varName));
}
HTML:
<li ng-repeat="mainList in itemsList">
<p ng-repeat="specificList in mainList">
<span>Id: {{specificList.id}}</span>
<br />
<span>Name: {{specificList.name}}</span>
</p>
</li>
Have a look at the demo.

Add item in array repeatedly for ng-repeat

I have an array of objects which looks like:
{
id: "1234",
general: {
title: "lorem",
body: "..."
}
}, ...
This data is being shown with an ng-repeat:
<ul>
<li ng-repeat="item in items track by $index">
<h2>{{item.general.title}}</h2>
<p>{{item.general.body}}</p>
</li>
</ul>
Now what I want to achieve is to add items to this list. Every 15 items I want to add a new item to the array to display in my ng-repeat. The item has a different structure:
<li>
<p>a text</p>
<a>a link</a>
</li>
So far I got this in my controller:
var addLinks = function addLinks(interval, array) {
var newArray = array.slice();
for(var i = interval - 1; i < array.length; i += interval) {
newArray.splice(i, 0, {
// Here comes the item to add
});
}
return newArray;
};
$scope.items = addLinks(15, articleService.articles);
My question is how do I add the item without just copying the html?
You could use ng-repeat-start and ng-repeat-end and only add the other element if you are on $index+1 % 15, like this:
<ul>
<li ng-repeat-start="item in vm.array track by $index">{{item.a}}</li>
<li ng-repeat-end ng-if="$index>0 && $index+1 % 15 == 0"></li>
</ul>
Here a plunkr: http://plnkr.co/edit/qwkXGcBcxlDy0hNHTvAo?p=preview
I would add additional properties to the item in question:
var addLinks = function addLinks(interval, array) {
//don't return a new array!
//var newArray = array.slice();
for(var i = interval - 1; i < array.length; i += interval) {
array[i].text = "foo";
array[i].link = "bar";
}
return array;
};
And in your view:
<ul>
<li ng-repeat="item in items track by $index">
<h2>{{item.general.title}}</h2>
<p>{{item.general.body}}</p>
<p ng-show="item.text">item.text</p>
<p ng-show="item.link">item.link</p>
</li>
</ul>

Angular.js interpolation in filter parameter

I have a filter on a ng-repeat, which accepts a parameter. It currently works with a string.
<div ng-repeat="(key, value) in searchData | aboutFilter:'abo'">
Is is possible to use an interpolated value in place of the string?
<div ng-repeat="(key, value) in searchData | aboutFilter:'{{list.api}}'">
Here is my filter:
app.filter('aboutFilter', function() {
return function(items, input) {
var filtered = [];
angular.forEach(items, function (value,key) {
if(key===input){
filtered.push(value);
}
});
return filtered;
}
});
Here is the complete template logic:
<ul ng-repeat="list in englishList">
<a ng-class="{{list.title}}Hide" mobile-search-slide href="/about"><li><p>{{list.title}}</p><i class="fa fa-chevron-right"></i></li></a>
<ul id="hideMe" ng-class="'hide{{list.title}}'">
<div ng-cloak ng-repeat="(key, value) in searchData | aboutFilter:'{{list.api}}'">
<div ng-repeat="result in value" ng-class-odd="'odd'" ng-class-even="'even'">
<a ng-href="{{value.title}}/{{result.shortname}}">
<li>
<p>{{result.title}}</p><i class="fa fa-chevron-right"></i>
</li>
</a>
</div>
</div>
</li>
</ul>
</ul>
If you want to use some ng-modelfor filter, then you can just use the model name. No need to use {{}} expression.
In your case, it will be :
<div ng-cloak ng-repeat="(key, value) in searchData | aboutFilter:list.api">
DEMO
Remember in your filter, you are using string comparison. So the filter will check for exact matches.
And also, IN your filter:
You are comparing key with the input list.api. Here key will always be 0,1, etc index. You must be using value there instead of key

Resources