2

I'm writing directive for multiple drag and drop using jQueryUI. Holding CTRL and selecting elements you can do multiple sorting. It works ok, except when element doesn't change position (I drag it, and then return it on same place). In that case, element is gone, although model is fine, and it displays all the elements correctly.

Here's the fiddle, for what I've done. http://jsfiddle.net/ndamnjanovic/swt48/3/

That's why I tried to manually insert HTML node, in case element is returned on same position. But in this case, after I insert element with ui.item.after(elements).detach(), elements lose associated actions (clicking on it doesn't trigger alertCity anymore). Here's the fiddle with other approach. http://jsfiddle.net/ndamnjanovic/EkVTW/11/

Any ideas what's the problem here?

2
  • Why are you using such an old version of Angular ? Commented May 12, 2014 at 13:22
  • yes, I add it by mistake, I see now. I'll change it, thanks for noticing. However I don't think that's the problem, cause in my project I have latest version and it's still not working. Commented May 13, 2014 at 7:43

1 Answer 1

1
+50

I think you've fooled yourself into thinking that Angular is managing this list for you (and me too, for the past hour ;) ). Because of the jQuery plugins you're using, the DOM for that sortable <ul> doesn't appear to be under Angular's control anymore. They probably re-rendered something at some point, wrapped it in a container, etc. But that means you are responsible for the DOM. After the drop, you need to re-insert the removed elements (draggedElements) into the correct position in the list.

Alternatively... you can trick Angular into managing the list for you. First, add ng-if="cities" to your sortable <ul>, then add this code at the end of your drop callback:

                var temp = scope.collection.slice(0);
                scope.$apply(function(scope) {
                    while (scope.collection.length) scope.collection.pop();
                });
                scope.$apply(function(scope) {
                    for (var i = 0; i < temp.length; i++) scope.collection.push(temp[i]);
                });

The ng-if directive causes angular to re-render the inner components (and re-initialize any inner directives) anytime the value changes from false to true. In this case, we use two calls to $apply to first give the collection a falsy value, and then restore its contents. This trips the ng-if wire and causes the list to re-render.

Example: http://jsfiddle.net/colllin/8dcXB/

Sign up to request clarification or add additional context in comments.

6 Comments

Hey, Collin, thanks a lot for helping me, I'm currently away from my working computer, I'll check this code as soon as I get near one :) Thanks a lot again!
BTW, I don't think the ngIf is necessary. ngRepeat will do the re-rendering if it detects changes in the list. I removed ngIf and it seemd to work file.)
Without your calls, it was all happening inside the same $digest loop, so ngRepeat could not see the difference (the city was removed from the array and then added back at the same index). Without any difference it didn't bother to re-render. But the jQuery (throught the sortable plugin) would have removed the DOM element (but ngRepeat just looks at the internal array, not the DOM).
With your $apply()s you first empty the cities array in one $diget loop (the first $apply()) then in the sacond $digest loop you populate it again (second $apply()). Thus , ngRepeat spots a difference in each cycle and re-renders the DOM. It is not a very efficient solution, but the code is rather complicated to spot the real problem and provide a better fix :D
Hey, I was stuck with another project, so finally I managed to take a look at this. Trick with $apply worked. Only one thing, instead of pop-ing and push-ing all of the elements of the array, I added $apply only when I remove dragged elements and return them back to list (places that already existed in code). Thanks again!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.