问题
I'm building a front-end to a mail-system. It's nicely split up in controllers and services. I'm using $interval to check for new mails, which gets received in JSON, and added to a model.
Everything gets rendered nicely to the screen with checkboxes to choose mails for deletions and buttons etc...
The problem is, that while a person is making choices - $interval will check for new mails, and replace the model-array with the incoming data, recreating the DOM and resetting all choices no matter if it contains new or the same data. The whole idea of the front-end is to avoid a user clicking "update" all the time.
I thought angular.copy could save me from headaches, but no... I read up on all kind of weird stuff about including dates in your model to diff between the incoming and existing model.
I can only come up with one solution for this problem, and that is to write functions myself that compare the incoming and existing array with all existing properties on both object. Fx. obj1.id == obj2.id then check properties, or add object if it doesn't exist.
I have been spoiled rotten in Knockout, because it deals with these kind of things. (when sending the same JSON array to an observable it will not recreate the dom - leaving my checkboxes/dom changes, alone).
Does anyone have a good solution for this problem or can anyone recommend a hack of some kind? I'm open to everything! I'm beyond desperate.
回答1:
I found a solution!
After poking around and further checking the "track by" with my scenarios, I can see that it actually does more what it says:
1) If you have a collection of objects, with each object having: id, name, description, you can, using 'track by' choose a property that it connects to, so, on retrieving a new collection of objects from a webservice, it will not render the DOM object belonging to the value.
2) Most importantly, and what I was after: If an object with an existing id arrives from the server with fx a changed name, will it be reflected in the array collection on the object with that id? Yes, it will! So, "track by" will actually check the properties of the incoming object and replace the old object and still leave the id alone. That's intense.
It's also worth noting that "track by" works also with other directives than ng-repeat, such as select.
I made a small demo, for other people who might be confused about how everything works... but it seems to be cool!
<div ng-repeat='country in countryArray track by country.id'>
{{country.id}}
{{country.name}}
<input type="checkbox"></input>
</div>
<div>
<select ng-model='nonExisting'
ng-options='country.name for country in countryArray
track by country.id'></select>
</div>
</div>
http://jsfiddle.net/KUf8C/
回答2:
AngularJS track by support on ng-repeat can help you here. By default it uses generated $$hashekey but this behaviour can be overriden. So if your records have unique ids you can use the track by to take care that the DOM is not reconstructed.
Ben Nadel did a post on this http://www.bennadel.com/blog/2556-Using-Track-By-With-ngRepeat-In-AngularJS-1-2.htm
回答3:
You should use an object to keep track of the selected emails.
Basically you keep a selected
object in your scope and use it to keep track of which emails are selected. For example if email 7 is selected then make selected[7] = true
.
So in psuedoish code
selected = {}
user selects email 7 then selected[7] = true
selected == {
7: true
}
user unselects email y then selected[7] = false
selected == {
7: false
}
Here is a jsFiddle that I might have gotten a little carried away with. I use the technique described above to keep track of which emails are selected.
http://jsfiddle.net/8kY9u/11/
In the fiddle I keep track of new emails in a similar fashion too.
来源:https://stackoverflow.com/questions/20509280/how-to-avoid-refreshing-ng-repeat-dom-list-when-array-is-updated