Duplicate Key in Repeater, track by creates problems - angularjs

I have an object I am trying to ng-repeat through.
The object is something like this:
ctrl.obj = {
"1": ["val1", "val2", ... ],
"3": ["val1", "val2", ... ],
...
"20": ["val1", "val2", ... ]
}
When I try:
<ul ng-repeat="item in ctrl.obj"></ul>
I get this angular error:
Error: ngRepeat:dupes
Duplicate Key in Repeater
The standard solution is to use track by $index. That does not work for my scenario though, because it now causes every integer between 0 and 20 to appear, even though I only have 1, 3, 7, 10, etc. I would ideally not like to reformat the object, as it is being loaded from outside the app ~ though this seems to be a recurring necessity with Angular.
What are my options for repeating through this object?

This object is a dictionary, where each property is a key, and each array is a value. To iterate through this properly, you would need two separate ng-repeat. something like the following:
<div ng-repeat="(key, value) in ctrl.obj">
{{key}} : {{value}}
<div ng-repeat="item in value">
{{item}}
</div>
</div>
There may be something else going on here, because I am unable to reproduce the error you are experiencing when using this syntax, though you state that the syntax causes an error in your situation. Can you post a sample of data which actually does cause this error?
http://plnkr.co/edit/LvvpxNqM6LuGVel4WQt9?p=preview
This plunker is using your original <ul>, and it is not producing any of the errors you are describing. It seems as though you haven't provided an accurate representation of the object you are trying to display here.
http://plnkr.co/edit/xgded2Ebrf0xKFuupOyr?p=preview
https://docs.angularjs.org/api/ng/directive/ngRepeat

Related

ngRepeat weird behaviour

I can not believe that i am unable to do the simple following object made up of two arrays
{"M":
[
"Alpha",
"Beta",
"Zeta"],
"F":
[
"Alpha",
"Omega"
]}
All i want to do is have a nested ng-repeat like the following
<a
class="list-group-item list-group-item-info"
ng-repeat="(key,list) in vm.result">
{{key}}
<a
class="list-group-item"
ng-repeat="name in list">
{{name}}
</a>
</a>
any one has any idea why it does not work.
It shows the key properly, but fails to iterate in the list and hence the name is not shown and no errors are shown in the console either
thanks
bottom line of your problem:
https://www.w3.org/TR/html401/struct/links.html#h-12.2.2
nested links are illegal
Links and anchors defined by the A element must not be nested; an A element must not contain any other A elements.
Since the DTD defines the LINK element to be empty, LINK elements may not be nested either.
Change your outer element to a <div> or <span> and it works

Angularjs: Ng-repeat and unique filter in array

I have a set of data like this
$scope.students = [
{ name:"John", courses:["Math", "Physics", "Chemistry"] },
{ name:"Paul", courses:["Economics", "Math", "Sociology"] }
]
I would like a way to filter using angular-filter so that I can get a list of all the subjects without repetition.
I've been trying to use unique filter, but I cannot get it to work since I try to iterate like
<ul ng-repeat="student in students">
<li ng-repeat="x in student.courses | unique:courses"></li>
{{x}}
</ul>
My desired output of the first ng-repeat would be an array like this:
["Math", "Physics", "Chemistry", "Economics", "Sociology"]
so I could iterate through it in the second one.
I have achieved this throught making a new scope with just the desired array, but then I cannot bind it properly, so I would like to achieve it through filtering. Thanks in advance.
I would really recommend you using the libraries Lodash or Underscore for this kind of problems. Learning to master these has helped me a lot!
Of course, you can create your own angular filter using one of them. The method you would like to use is union:
_.union(_.flatten(_($scope.students).pluck("courses")))
I use pluck to get out the courses arrays from the studens object, then I flatten the result (to get rid of the array that it comes nested in), and then i use union to get each subject only once.
If the requirement actually is to:
...get a list of all the subjects without repetition.
Then I would make a separate array for subjects:
$scope.courses = [];
// There are many ways to do skin this cat... (prograde does have a point!)
$scope.students.forEach(function(student) {
student.courses.forEach(function(course) {
if ( $scope.courses.indexOf(course) === -1 ) {
$scope.courses.push(course);
}
})
});
HTML
<ul>
<li ng-repeat="course in courses">
{{ course }}
</li>
</ul>
And if the students change I would recreate the courses-array.
But it sounds as if you are trying to do something else.
But it doesn't give the desired output.
It would help if you tell us what that desired output is!
http://plnkr.co/edit/bZNjIEFznvuyTU3zxAp1?p=preview

Looping in AngularJS not working

I'm trying a simple AngularJS looping using 'ng-repeat' directive as below :
<div ng-app="" ng-init="numbers=[1,3,5,2]">
<ul>
<li ng-repeat="item in numbers">{{ item }}</li>
</ul>
</div>
The result of this is as below, which is perfect
1
3
5
2
However, when I change the 'numbers' array like this
<div ng-app="" ng-init="numbers=[1,3,5,2,2]">
being the rest as is, it does not work.
The only change I have made is that I've added one more item in the 'numbers' array '2'. The issue I figured out is whenever an item is repeated in the array ( '2' in this case ), the problem occurs.
The console log I noticed is like below
Error: [ngRepeat:dupes] http://errors.angularjs.org/1.3.14/ngRepeat/dupes?p0=item%20in%20numbers&p1=number%3A2&p2=2
at Error (native)
at http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:6:417
at http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:232:494
at Object.fn (http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:122:53)
at l.$get.l.$digest (http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:123:138)
at l.$get.l.$apply (http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:126:58)
at http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:17:479
at Object.e [as invoke] (http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:36:315)
at d (http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:17:400)
at tc (http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:18:179)
Also, if the array is of string type values, the same problem persists too.
For example, <div ng-app="" ng-init="names=['Bishnu', 'Sagar', 'John', 'Bishnu']">
in this case also I'm facing the same issue.
This behavior of AngularJS is very strange.
Does anyone know the reason, and how to resolve?
Try this...
The ngRepeat directive instantiates a template once per item from a collection. Each template instance gets its own scope, where the given loop variable is set to the current collection item, and $index is set to the item index or key.
ngRepeat makes the corresponding changes to the DOM
When an item is added, a new instance of the template is added to the DOM.
When an item is removed, its template instance is removed from the DOM.
When items are reordered, their respective templates are reordered in the DOM.
By default, ngRepeat does not allow duplicate items in arrays. This is because when there are duplicates, it is not possible to maintain a one-to-one mapping between collection items and DOM elements.
If you do need to repeat duplicate items, you can substitute the default tracking behavior with your own using the track by expression
<div ng-repeat="n in [42, 42, 43, 43] track by $index">
{{n}}
</div>
Refer:https://docs.angularjs.org/api/ng/directive/ngRepeat
As per the Angular Docs Duplicates are not allowed. You need to use 'track by' expression to specify unique keys.
Created this Plnkr for your reference
<div ng-app="" ng-init="numbers=[1,3,5,2,2]">
<ul>
<li ng-repeat="item in numbers track by $index">{{ item }}</li>
</ul>
</div>
You need to use track by $index to iterate through duplicate entry as well.
you can try like this
<div ng-repeat="value in [4, 4] track by $index">{{value}}</div>

ng-repeat over array of objects vs. object containing objects

In almost all the examples of ng-repeat I've seen, the data is structured like so:
$scope.dataCollected = [{name: bob, data: '10-12-12'}, {name:joe, data: '09-13-13'}];
However, the only way I can get ng-repeat to work is if I structure the data like this:
$scope.dataCollected = {bob: {name: bob, data: '10-12-12'}, joe: {name:joe, data: '09-13-13'}};
Structuring it as an array causes the ng-repeat to do absolutely nothing. It doesn't even give an error. Structuring it as an object containing objects works, but I'd like to use an array because I understand it's the only way to use a filter on ng-repeat.
I'm calling the ng-repeat like this:
<div class="list-row" ng-repeat="data in dataCollected">
<h3 class="name"> {{data.name}} </h3>
</div>
What am I missing?
Sorry guys, thank you for the help. The issue was that in an attempt to make my data easier to read, I had assigned names to the keys of the array using bracket notation as seen in the answer here: stackoverflow.com/questions/12244483/… ng-repeat does not like that at all. It seems the default keys are necessary.

AngularJS not able to include markup in IDs?

I have an array of 3 items and want them to be "ng-repeated"
<li ng-repeat="item in obj.items id="testobj{{testobj.number}}">
</li>
When I look at the page, it appears that the id of the "li" is just "testobj" for all 3 items and not testobj1 testobj2 testobj3 like I was expecting. What is the issue?
Your ng-repeat attribute is missing a final ".
The {{ }} binding is probably coming back with no data and so being treated as if it was an empty string. I see no reference to testobj (the scope variable) anywhere outside of your binding. Is this defined, or should your id read id="testobj{{item.number}}" or something similar?

Resources