Handling duplicate elements in ng-repeat

I am creating an application in which there is a kind of β€œplaylist”. This is an ng-repeating user directive with ng-repeat = "element in playlist"

Since I want to allow the user to reuse the same item twice in the playlist, I tried using the track by $index add-on.

Now, what is confusing: when I came to remove an item from a playlist (I have a removeElement(index) function that essentially contains something like this:

 $scope.removeElement = function(index){ $scope.playlist.splice(index, 1); } 

Something strange happened: the item was deleted correctly from $scope.playlist , but for some reason the view did not refresh properly. The last item was deleted.

Also, I was not able to properly reorder the elements in the array.

When I deleted track by $index , this problem will disappear, so I assume that this is because when you remove an element from an array, if you look only at indexes, then it looks like you just deleted the latter.

The behavior is odd, though, because the translated content is correctly deleted - see this plunger

EDIT: The above link has been modified to show the problem better, as well as show the answer I stopped for.

The question has also been slightly edited to make it clearer what I'm referring to. The KayakDave answer below is still correct, but more suitable for an array of primitives (which was shown by my original plunger).

TL DR: How do you add repeating elements to ng-repeat without sacrificing the ability to control your position or delete elements correctly?

+6
source share
2 answers

I would like to add another answer to this question, because I found a simpler solution.

There is an important section of documentation for ng-repeat that is easy to skip, especially in case of a cheating error.

It states:

By default, collections are entered by reference

After reading this solution, it was obvious - since I was not dealing with primitives (yes, there is a plunker, but it was an oversimplification) I needed to copy the duplicated object and add its copy to the array. This means that everything works as expected when you delete a track at $ index and just let it use the default behavior.

Angular makes this especially easy because jqlite has .copy . Method.

This is what I say demonstrated in the plunker .

+5
source

One of the great benefits of using track by is Angular does not apply to any DOM element whose tracking expression has not changed. This is a big performance improvement for long ng-repeat lists and one of the reasons for adding track by .

This performance optimization is at the core of what you see.

When you use $index in track by , you say ng-repeat to bind each DOM element, it creates a position ( $index ) in it the first time you run ng-repeat .

So, the element with red red is marked 0, orange 1, yellow 2 ... and finally indigo 5.

When you remove the Angular color, look at the indexes you told it to track and see that you have more index number 5 (since your list is shorter than before). Therefore, it removes the DOM element with tags 5-, which has an indigo color style. You still have index C # 2, so the yellow element remains.

What is perplexing is that, due to data binding, the text inside the DOM element is updated. That way, when you delete the yellow, the yellow DOM element gets the text green.

In short, you see ng-repeat leaving the DOM element in the style of yellow untouched because its tracking value (2) still exists, but the data binding updated the text inside that element.

To add multiple records with the same color , you need to add your unique identifier to each record that you use for track by . One approach is to use key-value pairs for each record, where the key is your unique identifier. For instance:

 $scope.colorlist = {1:'red', 2:'orange',3:'yellow',4:'green',5:'blue',6:'indigo',7:'yellow'}; 

Then track by key as follows:

 <color-block ng-repeat="(key, color) in colorlist track by key" color="{{color}}" ng-transclude> {{color}} </color-block> 

And be sure to use this key to select delete:

 <option value="{{key}}" ng-repeat="(key,color) in colorlist">{{color}}</option> 

Now the yellow DOM element will be bound to the key specified for the yellow element. So when you remove the yellow, ng-repeat will remove the correct DOM element and everything will work.

You can see how it works here: http://plnkr.co/edit/cFaU8WIjliRjPI6LInZ0?p=preview

+7
source

Source: https://habr.com/ru/post/958997/


All Articles