Skip to content
This repository was archived by the owner on Mar 10, 2024. It is now read-only.

How do i use that directive with ngRepeat using track by? #96

Closed
kadosh1000 opened this issue Jul 22, 2015 · 11 comments
Closed

How do i use that directive with ngRepeat using track by? #96

kadosh1000 opened this issue Jul 22, 2015 · 11 comments
Labels

Comments

@kadosh1000
Copy link

Hi, whenever i use track by on my ngRepeat, especially "track by $index" it causes a lot of trouble, what is the best way to use it with track by?

@marceljuenemann
Copy link
Owner

track by $index is a very primitive way of tracking and will not work in this case. The important thing with ng-repeat is to have a way of to differentiate otherwise equal objects, e.g. create a UUID field in the object. Luckily, angular automatically adds a $$hashKey field for this, and implicitly tracks by $$hashKey.

So my recommendation is not to use track by at all and let angular take care of it. Why do you want to use it anyways?

@kadosh1000
Copy link
Author

Using ngRepeat without track by causes a very well known preformance issue in angular, adding track by saves a lot of cpu power and enhances tge preformance. I will try to use the $$hashKey as I have no other constant field on that specific model

The thing is that in that array i have models brought from the server containing ID and new items that weren't uploaded yet that don't have any id.

edit:
track by using $$hashKey not working, I have no idea why buy I receive multiple dupes error, for now I temporary removed the track by completely until i'll figure out a solution.

@marceljuenemann
Copy link
Owner

Using ngRepeat without track by causes a very well known preformance issue in angular, adding track by saves a lot of cpu power and enhances tge preformance.

I don't believe this is true in general, as it automatically tracks by $$hashKey. You only get into performance problems if you do anything to the $$hashKey fields, e.g. replacing the entire list will generate new $$hashKeys and therefore rerender the whole DOM.

Did you actually measure the performance of your application? How big is your list?

@kadosh1000
Copy link
Author

The list containing the issue is small, so it's not such a big issue, the thing is that it is very recommended by the angular team to use track by on all ngRepeats as it improves performance significantly as you can see in almost every article concerning angularJS performance. for now i just removed the track by

@marceljuenemann
Copy link
Owner

I think you're optimizing prematurely, but if you really want to use track by, just choose a field on your object that is unique, and make sure to update it in the dnd-drop callback, so that there are no duplicates.

@edgar0011
Copy link

Well the problem is, the moment when you remove item from list and add it to a new place, to same objects ar in ng-repeate. I got the same issue, trakby on unique ID from Database, and still got duplicate error:

Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: payment in payBillCtrl.payments | filter:search track by payment.id, Duplicate .............
at :9000/dev/lib/angular/angular.js?v=tbc1440069489908:68
at ngRepeatAction (:9000/dev/lib/angular/angular.js?v=tbc1440069489908:27144)
at Object.$watchCollectionAction as fn
at Scope.$digest (:9000/dev/lib/angular/angular.js?v=tbc1440069489908:15685)
at Scope.$apply (:9000/dev/lib/angular/angular.js?v=tbc1440069489908:15953)
at HTMLUListElement. (:9000/dev/lib/angular-drag-and-drop-lists/angular-drag-and-drop-lists.js?v=tbc1440069489908:323)
at HTMLUListElement.eventHandler (:9000/dev/lib/angular/angular.js?v=tbc1440069489908:3273)

@tonysyu
Copy link

tonysyu commented Oct 20, 2015

I see the same issue when using track by with ng-repeat. If I understand things correctly, the workflow looks like the following:

  1. When a dragstart event is fired, the item dragged out of the list is copied (more or less) but left in the list.
  2. When a subsequent drop event is fired, the copied item is added to the list in the new location.
  3. Finally, the original item is removed (assuming dnd-move is properly defined) when the dragend event is fired.

Between steps 2 and 3, there's a duplicate element in the list, which is why ng-repeat complains.

I imagine that leaving the original element in the list is important for how canceled drags are handled, so a fix might be a bit involved.

@marceljuenemann
Copy link
Owner

I see the problem. One workaround would be to use dnd-drop to remove the old element / invalidate all elements with the same ID by setting the ID to null. I don't have any idea how to solve this cleanly right now.

@bartonsprings
Copy link

I have the similar issue but I track by a unique item ID property for my object (not $index). In my case some nested lists do see a performance impact by not using trackby. So unfortunately, I have to use the track by ...

Is it possible to:

  1. Let user specify an attribute for property name they are tracking by, something like: track-by-id="myID".
  2. You then look in the item object to see if that property exists.
  3. If it exists, then when copying the item before moving the object, you generate a fake/temp property for that item object and use the original value in this property. Now delete that original property from original object. Since the element is hidden this should not cause any issue.
  4. After item is dropped, anyway the old item will be delete. If drop failed then simply recreate the original ID from temp property and release the item to be shown.

Could possibly also have the case that if user attribute track-by-id=0 then it means they are tracking by $index and all other cases it is simply user specified tracking property name.

Would this work?

@johannesjo
Copy link

johannesjo commented Jan 2, 2017

I think that this is not just about performance. The directive is buggy sometimes when working with multiple lists and I'm pretty sure that is caused by its reliance on the default tracking by hash which is often unreliable.

Some examples: Sometimes when working with 2 lists when dropping one item to the other overwrites some other item or when deleting an item sometimes another one in the wrong list is deleted.

@marceljuenemann
Copy link
Owner

With the new dnd-callback you can implement move by reference like this: https://jsfiddle.net/Ldxffyod/1/ In that case there are no more duplicate items in the list, and tracking by a custom property should work without weird fake properties or hacks. Small caveat is that this does not work with dnd-external-sources, but I assume that's no problem for most people.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

6 participants