I have a problem with the refresh button in my Angular application:
I have a json object with two arrays in it -> data = {array1: [], array2: []}
I want to loop both arrays and print the related values. To achieve that, I use the Angular ng-repeat directive like this:
ng-repeat="index in [] | index:getTotalNumberOfObjectsInArray1()"
...
<span ng-bind="data.array1[index]"></span>
<span ng-bind="data.array2[index]"></span>`
My Problem is, that on every click on the refresh-button these data will be recreated on the dom.
I learned the documentation about "track by" but i understand it only on objects (for example: ng-repeat="a in objects track by a.id")
How can I use this track by filter for my ng-repeat above, to prevent the recreation of my data?
You can use $index that is defined in a ng-repeat (cf.doc) but you have to have the two array with the same length.
Another solution could be to merge your arrays together and loop on it but I am not sure if it answer to your question.
Related
Using Angularjs, Created a search with ng-repeat (2 levels) and populate divs with results, How do remove the search result when a new search is requested
<table>
<div ng-repeat="one in all" >
<div id="resultTableParent" ng-repeat="two in one">
<div id="results">{{two.details}}</div>
</div>
</div>
</table>
you can pass an empty array to all: $scope.all= [] or put the new results instead: $scope.all = newResult
You just must put the new results on the variable of your controller("all" in your case), using the two way databinding angular feature. If you want only clear the results, so clean the "all" variable.
Your ng-repeat uses the array $scope.one, so any modifications to it will be updated in the ng-repeat. If what you're trying to achieve is replacing it just populate it again with the new results. If you want it to appear empty you can empty the array using
$scope.one = [];
Since this is a two level ng-repeat, I added:
$scope.all.items = []
The 'items' were what was holding the result in to "one" (in first ng-repeat)
Thank you all for responding and opening the doors.
I have a problem with angular ng-repeat directive.
Currently I work on some project where from the API I get a list of items (some times it could be 1k items) and this list should be refreshed every 5 seconds (it is monitoring related project).
When the list length is a little bigger the website while re-rendering DOM could "slow". It comes out that angular regenerate the whole DOM (but 95% of item are the same ! )
One of the possible approach is to set "track by" expression for example to item.id. But here comes another problem, I also want regenerate items when for example descriptions was changed by other user. Since track by is expression to item.id changes in item.description didn't update item in DOM.
There is way to track by over multiple properties? Maybe some function?
Or maybe do comparison by "hand" ?
Any ideas, code samples I would appreciate :)
UPDATE
what I discover when I set track by to item.id angular didn't re-crete html for items, just update value in already created element and it seems to be "faster" then removing and creating.
Previously I though a little bit different.
FIX
For those who are looking for better performance over >1k items in ng-repeat USE track by item.id it will boost your performance ;)
You do not need to create a function to handle track by multi properties.
You can do:
<div ng-repeat="item in lines track by item.id+item.description">
As the comment suggested you could try something like this:
<select ng-model="item" ng-options="item.id as item.description for item in items track by itemTracker(item)">
In your controller:
$scope.itemTracker= function(item) {
return item.id + '-' + item.description;
}
This might help with the number of DOM elements being re-rendered when the list changes.
Based my knowledge, the angularjs model is bind to the ui view, so the model will rerender via $apply or $digest once the value changed. so in your case, u wan bind the model value to ui view but also do not want to re-render the view if the value has not change,that is impossbile. this is what i know.
however, u can just manipulate the dom element. for example
store the data to a variable
var x = [{id:"id1",value:"v1"},{id:"id2",value:"v2"}]
in html, manual append or using directive to append, then assign the id to the element,
<div id="id1">v1</div>
check and compare the value, based ur needs.
once found, then angular.element("#yourid").text()
this will solve your browser resources consume problems.
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.
Okay, I have a weird issue. I have an array of objects. Each object contains another array (of strings). I loop over the array of objects using ng-repeat. Within the repeated code I ng-repeat over the array of strings. For some reason, this nested ng-repeat only works when the array of strings contains but one (1) item. When there are more items, it simply doesn't work.
Code
Result of <pre>{{ answer.value | json }}</pre>
[
"Apothekerskast",
"Apothekerskast",
"Koelkast ombouw"
]
The view (in a gist because posting here causes issues with markdown): https://gist.github.com/fabdrol/898e4ac9760fc358ce81
The data (in JSON), for easy reading: https://gist.github.com/fabdrol/089467fa09dad6e89e81
It doesn't like duplicates, use track by $index:
ng-repeat="val in vals track by $index"
JSFiddle: http://jsfiddle.net/nedq13q2/
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'