ng-repeat value in array with same name - arrays

In my array there is multiple key value having same name . I want to list them all in my View how can I achieve that ?
I am facing error stating [ngRepeat:dupes] Duplicates in a repeater are not allowed.
This is my JSON array :-
["text-align", "space-before", "space-before.conditionality", "font-size", "font-weight", "line-height", "font-size", "font-weight", "line-height", "space-before", "font-size", "font-weight", "line-height", "position", "top", "bottom", "right", "left", "text-align", "force-page-count", "break-before", "font-size"]
As we can see few keys are repeating . I need to list all repeated values without missing any in my View

You you use ng-repeat it loops over the unique values in the array. If you have duplicate values then you need to explicitly mention the Angular module to ignore the values to be unique and look for unique index value, by doing:
ng-repeat = "item in items track by $index"
Using track by you can explicitly mention that which value should be checked as a uniqueness measure while rendering the DOM using ng-repeat. You can even use the property of the object like item in items track by item.id where item is a object having id property and items is a array of objects.
Your array has font-size specified multiple times in the array so use track by $index.

You can use track by $index to remove this error, something like this
<tag ng-repeat="item in items track by $index">
//content
</tag>
https://docs.angularjs.org/api/ng/directive/ngRepeat

Related

Save filtered ng-repeat in a new variable

How can I save this filtered ng-repeat in a new variable?
<div ng-repeat="Item in AllItems | filter: { Type: 'test' } | filter: searchByItem as results">
I want to do this because I need the length of the filtered array for the pagination.
Within ng-repeat, when you use as to create alias results that filtered array will be added to the scope that the element exists in.
Therefore you can use {{results.length}} to see the length in view outside of the ng-repeat and should be able to pass results to other directives

NG-Repeat doesn't update cleanly when scope is updated

So I have a list of workspaces:
<li class="workspace-object" ng-repeat="w in workspaces | filter:searchQuery" ng-click="selectWorkspace(w)">
{{w.name | titleCase }}
</li>
That List gets updated in the database by some function, and then I call the loadWorkspaces function below, to re-populate the $scope.workspaces object
$scope.loadWorkspaces = function() {
APIService.getWorkspaces().then(function(data){
$scope.workspaces = data;
});
}
When this happens, the $scope.workspaces, when logged out, reads the right updated information immediately, however, the ng-repeat DUPLICATES, before it updates to the proper list. I have no idea why this happens. Any ideas?
In this example, I am updating the workspace title, and that update runs the loadworkspaces function.
Try this ...
w in workspaces track by $index
When the contents of the collection change, 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.
For example, you may track items by the index of each item in the collection, using the special scope property $index
Accepted answer did not help me (Using Angular 1.1.10), my repeat was still updating delayed. I struggled for ages before I got it working.
Instead of repeating my custom directive like so;
<my-directive ng-repeat="item in myarray track by item.id" some-binding="item"></my-directive>
I (magically) got it working after moving the ng-repeat to a (non-directive) parent element, like so:
<div ng-repeat="item in myarray track by item.id">
<my-directive some-binding="item"></my-directive>
</div>

AngularJS - original index of an object within filtered ng-repeat

I am using a nested ng-repeat and a filter on a object. The first ng-repeat is filters to the headerId in a gapHeader object. The second ng-repeat filters gapSection, sectionId to the corresponding headerID.
I have an edit page which is within a separate modal window. The purpose is to edit content corresponding to the headerID & sectionID of the sub-object) This also has a separate control. Data is shared through a service.
My problem I have a button for each gapSection sub-object, which opens the edit page modal, when I pass the $index value for the current section within each section to the service, I get the $index only corresponding to the second ng-repeat? For example, if I click the button within the 2 ng-repeat on gapSection (headerId:2, sectionId:2), I get an $index of 1. I require an $index of 2 which corresponds the sub-object position within gapSection.
Is it possible to pass the true $index which corresponds to the $index defined in the original un-filtered object of gapSection? Appreciate any comments on this and thank you!
Object:
var data ={
gapHeader:[{headerId:1,name:"General Requiremets",isApplicable:true},
{headerId:2,name:"Insurance",isApplicable:false}],
gapSection:[{headerId:1,sectionId:1,requirement:"A facility is required to have company structure",finding:null,cmeasures:null,cprocedures:null,personResp:null,isAction:null},
{headerId:2,sectionId:1,requirement:"Organisation must have public liablity",finding:null,cmeasures:null,cprocedures:null,personResp:null,isAction:null},
{headerId:2,sectionId:2,requirement:"Facility must hold workers compensation insurance",finding:null,cmeasures:null,cprocedures:null,personResp:null,isAction:null}]
};
If you need the true index you do not even need to pass the $index property, just pass the object and get the index from the original list.
i.e
$scope.gapSectionFn = function(obj){
var idx = data.gapSection.indexOf(obj);
}
Also it is not clear your issue could really be a nested ng-repeat issue, because according to you gapSection is the inner ng-repeat and you are invoking the call from inner ng-repeat and in need of gapSection's index. It should just be available, but the presence of a DOM filter will just reorg the items and its index which you can also get by doing an ng-init, i.e on the view ng-init="actIndex=$index" and use actIndex.
If you are trying to access parent ng-repeat's index then, ng-init is more appropriate than $parent.$index. Since ng-init is specially designed for that., on the parent ng-repeat you would write ng-init=""parentIndex=$index" and use parentIndex.

ngRepeat:dupes - duplicates in repeater with nested ngrepeat and empty strings

I'm working with angular building a table of data which comes from a JSON API call. I'm having to use a nested ngRepeat however I'm seeing strange results where whole table rows are missing when the row has a couple empty strings.
I can reproduce with the following plunk.
http://plnkr.co/edit/VCzzzPzfgJ95HmC2f83P?p=preview
<script>
function MyController($scope){
$scope.test = {"rows":[
["one","two","three"],
["one","two","three"],
["one","","three"],
["one","",""],
["","two",""],
["","","three"],
["one","two","three"],
["one","two","three"],
]};};
</script>
<div ng-app ng-controller="MyController">
<table>
<tr ng-repeat="(key,ary) in test.rows">
<td>{{key}}</td>
<td ng-repeat="value in ary">{{value}}</td>
</tr>
</table>
</div>
Notice when an array has two empty strings the nested ngRepeat appears to fail.
Am I going mad? Is there an explaination to this?
Yes. You would need to use track by $index since you are repeating primitives, or convert it to array of objects. Reason is ng-repeat creates unique id $$hashkey (and attached to the repeated object as property) for each of the iterated values if it is an object (unless you specify something as track by).
In your case you have primitives so it cannot attach a property itself, so it tries to consider the values repeated as identifier and it finds duplicate when you have multiple empty strings iterated. You would see the same effect when you repeat array of objects with more than one of them is undefined or null as well..
So in this case you can use track by $index So repeated items will be tracked by its index.
<td ng-repeat="value in ary track by $index">{{value}}</td>
Demo
Much better option always is to convert it to array of objects so you don't run into these kinds of issues. WHen you have a property that uniquely identifies the repeated element (say id) you can set it as track by property. When you rebind the array (or refresh the array) angular uses the tracked identifier to determine if it needs to remove the element from DOM and recreate it or just refresh the element that already exists. Many cases where a list is refreshed with the list of items it is always desirable to use a track by with an identifier on the object repeated for performance effectiveness.

ng-repeat not working over collections that contains dupes

The following code is not working because the collection contains dupes:
<div ng-repeat="value in [4, 4]"></div>
I think that the following should work but is unfortunately not working:
<div ng-repeat="value in [4, 4] track by $index"></div>
Is that a bug?
Is there a way to use ng-repeat over a collection that contains dupes?
Thanks in advance,
Olivier
This feature has been added to AngularJS in newer versions.
the point is that basically you should not iterate over some primitive types (e.g. numbers) but over some complex objects.
from what I've understood the ngRepeat directive checks the references not the actual values so if you iterate over some complex objects it woks but if you try to do that over a set of primitive types it will most likely not work as long as "all" the values differ from one another.
EDIT
The following lines are copies and pasted from this link (and make sure you are using a relatively up-to-date version of AngularJS - I'm using 1.1.5 and it's working perfectly -)
Description
Occurs if there are duplicate keys in an ngRepeat expression. Duplicate keys are banned because AngularJS uses keys to associate DOM nodes with items.
By default, collections are keyed by reference which is desirable for most common models but can be problematic for primitive types that are interned (share references).
For example the issue can be triggered by this invalid code:
<div ng-repeat="value in [4, 4]">
</div>
To resolve this error either ensure that the items in the collection have unique identity of use the track by syntax to specify how to track the association between models and DOM.
To resolve the example above can be resolved by using track by $index, which will cause the items to be keyed by their position in the array instead of their value:
<div ng-repeat="value in [4, 4] track by $index"></div>
One thing you can do is add "track by $index" as in angular documentation which will change the tracking logic to index of the element rather than value of the element, but this will display the repeated values. To display only unique values you can filter out the unique values by writing a function like :
var uniqueValues = function(data){
var check = {};
var uniqueValue = [];
for(i-0;i<data.length;i++){
if(!check[data[i]]){
uniqueValue.push(data[i]);
check(data[i]) = true;
}
}
return uniqueValue;
}
and then do a ng-repeat on this.
The Angular Filter 3rd party filer contains a 'unique' filter that will give you just the unique entries in your collection.
https://github.com/a8m/angular-filter
Usage:
collection | unique: 'property'

Resources