Angularjs ng-repeat: how to detect a collection vs an array - angularjs

I need to repeat over either a collection or an array, depending on the situation.
How Would I do that, provided the following approach causes "ngRepeat: dupes", code snippet as follows:
<div ng-if="cause.length" ng-repeat="k in cause">
{{k}}
</div>
<div ng-if="!cause.length" ng-repeat="(k,v) in cause">
{{k}}
</div>

add track by $index to end of ng-repeat declaration any you will not get any Dupes error...
<div ng-if="cause.length" ng-repeat="k in cause track by $index">
{{k}}
</div>
<div ng-if="!cause.length" ng-repeat="(k,v) in cause track by $index">
{{k}}
</div>
UPDATE
If no tracking function is specified the ng-repeat associates elements by identity in the collection. It is an error to have more than one tracking function to resolve to the same key. (This would mean that two distinct objects are mapped to the same DOM element, which is not possible.)
and this explanation from angularjs documentation explains why it resolve this error...

Related

ng-repeat is not showing data but shows correct length

I have a strange problem with showing some data using ng-repeat.
If my markup code is this:
<p ng-repeat="d in data"> {{d}} </p>
nothing shows up however if i do
<p> {{data}} </p>
the following is shown:
[203507,"Giannis","Antetokounmpo","Giannis Antetokounmpo","Antetokounmpo, Giannis","G. Antetokounmpo","1994-12-06T00:00:00","Greece","Greece","Greece","6-11","222",3,"34","Forward","Active",1610612749,"Bucks","MIL","bucks","Milwaukee","giannis_antetokounmpo",2013,2016,"N","Y"]
I checked the length of the array using {{data.length}} and it says 26 which is accurate. someone please explain?
my code to get data in scope is a json object:
$scope.data = info.resultSets[0].rowSet[0];
When you have duplicate values in the array you need to add 'track by $index'
<p ng-repeat="d in data track by $index"> {{d}} </p>
You're facing this issue because your array contains duplicates, you can check further information here

AngularJS: what is the usage of track by with ng-repeat

i am new in angular and i go through this doc https://docs.angularjs.org/api/ng/directive/ngRepeat but do not understand the objective of track by clause using with ng-option.
here are few usage
<div ng-repeat="n in [42, 42, 43, 43] track by $index">
{{n}}
</div>
<div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
{{n}}
</div>
<div ng-repeat="model in collection track by model.id">
{{model.name}}
</div>
<div ng-repeat="obj in collection track by $id(obj)">
{{obj.prop}}
</div>
<div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by model.id">
{{model.name}}
</div>
track by is something close to order by clause in sql ?
if yes then how can i specify sort order like ASC or DESC ?
in last code track by and orderBy both use....what they are doing. not clear what kind of output will come.
what is difference between orderBy & track by ?
orderBy is filter that i know. so track by is also a filter.
i know i am asking very basic question. basically posting here because things is not clear after reading it from doc. looking for some help and example to understand what track by does ?
how track by is different from orderby in terms of usage ?
By default orderBy will be in ascending order. You can use "reverse" for descending order like
In HTML Template Binding
{{ orderBy_expression | orderBy : expression : reverse}}
In JavaScript
$filter('orderBy')(array, expression, reverse)
If you do need to repeat duplicate items, you can substitute the default tracking behavior with your own using the track by expression.
For example, you may track items by the index of each item in the collection, using the special scope property $index:
`<div ng-repeat="n in [42, 42, 43, 43] track by $index">
{{n}}
</div>`
ngRepeat uses a function to "keep track" of all items in the collection and their corresponding DOM elements
If a new item is added to the collection, ngRepeat will know that all other items already have DOM elements, and will not re-render them.
See the detail
If you have object for ngRepeat and it have any identity field (Like primary key value or Unique value), use it in track by.
Good thing is that if you are re-loading the list, dome will not re-render for existing items but only the new ones.

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>

AngularJS : How do I bind ng-model to an array inside a ng-repeat

I can't seem to make my multiple dropdowns to work.
<div ng-repeat="i in [0,1,2,3,4] track by $index">
<select ng-model="myArray[i]" ng-options="someList"></select>
</div>
In the html the result is ... ng-model="myArray[i] instead of ng-model="myArray[0] etc.
I have tried curly brackets but it doesn't work. closest thing was ng-model="myArray['{{ i }}'] but that' not really what I want.
Edit: Here is a fiddle to illustrate.
http://jsfiddle.net/dpkzzyug/1/
You need to examine the HTML to see that the result literally writes out i (or $index in this case) instead of the value.
The code that you have works, but the problem is that myArray is local to the ng-repeat scope. You need to make sure that myArray exists outside of this scope.
Something like the following will work:
<div ng-app ng-init="someList=[1,2,3]; myArray = []">
<div ng-repeat="i in [0,1,2,3,4] track by $index">
<select ng-model="myArray[i]" ng-options="i for i in someList"></select>
http://jsfiddle.net/778x0pm0/1/
I would personally prefer to use the controller as syntax since this makes this a little clearer:
<div ng-app=app ng-init="someList=[1,2,3]">
<div ng-controller="ctrl as ctrl">
<div ng-repeat="i in [0,1,2,3,4] track by $index">
<select ng-model="ctrl.myArray[i]" ng-options="i for i in someList"></select>
http://jsfiddle.net/778x0pm0/
I just realized that the html will write out i / $index even though the logics of angular still work. I was having problems elsewhere and thought it was because of this.

Iterating over a list and calling directives depending upon the item types , in angular js

I have a HTML file it iterates over a list of objects as shown and every object has a template( stored in the db) that it uses I get "List" from a web service :-
<ul>
<li ng-repeat="object in List" ng-include="object.TemplateName" > </li>
</ul>
Let object.TemplateName be "template1"
A sample template would have a specific directive with the attributes needed and few html tags as shown "template1":-
template1:-
<directive1 s-web-service-path="object.WebServicePath" >
<h1>any html content</h1>
</directive1>
my directive calls a web service to get the content to be displayed and has its own template... instead of putting directives in a template and including them cant I directly call my directive depending upon the different types of objects that i obtain in List
something like
for Object.Type="1" i call directive1 instead of template1
for Object.Type="2" i call directive2 instead of template2
ngIf or ngSwitch might be helpful here, with a few extra wrapping elements within the ngRepeat, in order to dynamically choose what to include based on Object.Type. Using ngSwitch:
<ul>
<li ng-repeat="object in List">
<div ng-switch="object.Type">
<div ng-switch-when="'1'">
<div ng-include="object.TemplateName"></div>
</div>
<div ng-switch-when="'2'">
<directive1 s-web-service-path="object.WebServicePath" >
<h1>any html content</h1>
</directive1>
</div>
</div>
</li>
</ul>
The above is not tested, so there could potentially be an error. You might also be able to cut down on some of DOM nesting level by including the ng-switch-when attributes on the directive1 / ng-include divs, but the way above makes the behaviour clear, and avoids any unexpected issues that might arise from having multiple directives work on the same element.

Resources