Skip to content
This repository has been archived by the owner on Sep 8, 2020. It is now read-only.

canceling drag between connected lists drops item #107

Closed
brendanblackwood opened this issue Jan 28, 2014 · 12 comments
Closed

canceling drag between connected lists drops item #107

brendanblackwood opened this issue Jan 28, 2014 · 12 comments

Comments

@brendanblackwood
Copy link

I'm trying to cancel dragging an item from one list to another if certain conditions are met (in the example, max list size).

http://codepen.io/anon/pen/toDej

Try to have more than 10 things in one of the lists. Visually, there are no problems, but if you log out the results, you see items are getting removed from one list and not put back. It could be that I'm approaching this wrong, but I'm running out of ideas.

Oh, and I am using the angular1.2 branch.

@thgreasi
Copy link
Contributor

You should use the model to count the length of the list, not the DOM elements.

@ghost ghost assigned dimirc and thgreasi Jan 29, 2014
@brendanblackwood
Copy link
Author

Fair enough. The same problem will persist, however. Canceling the sort will replace the item in the proper place in the DOM, but it will not replace the model. That just gets lost.

New codepen with model checking: http://codepen.io/anon/pen/fAvCJ

@thgreasi
Copy link
Contributor

Here is the order that the events fire on connected lists:

strart      0
activate    1
activate    0
update      0
remove      0
receive     1
update      1
stop        0

As far as I know the best time to call cancel() is inside the first update callback. Receive and update on the receiving list is too late, since the first model has already been altered.
Here is a pen utilizing the changes of #108.

Feel free to reopen if necessary.

@brendanblackwood
Copy link
Author

Works great. Thanks!

@jegesh
Copy link

jegesh commented Mar 14, 2016

How would I go about cancelling a drag between lists, but allowing ordering within a list, only for certain elements (validation)? When I try to cancel when remove fires from the original list, the element stays put, but becomes unorderable thereafter. Debugging it, I see that ui.item.sortable.model is undefined.

@thgreasi
Copy link
Contributor

You can place your logic in the update callback and use the properties of
the ui.item.sortable object (ui is the second argument of the callback).
Take a look at the examples and documentation in README.md and API.md .

Thodoris Greasidis
Computer, Networking &
Communications Engineer

@jegesh
Copy link

jegesh commented Mar 14, 2016

I tried doing that, but I need to know if it's just a sort within the list, or moving to a second list. There is no indication of this until either the second update is hit, or remove of the first list gets hit, in either too late to cancel the action, because the update call of the original list happens before that. I'm looking for a way to either determine already in the first update if it's a move or an ordering, or alternatively a way to 'manually' call the update callback from within the remove callback of the same list.

@thgreasi
Copy link
Contributor

As noted in API.md, you can use the droptarget and droptargetModel properties and possibly compare them with source and sourceModel properties, to check whether it's a connected-list sorting.

@thgreasi
Copy link
Contributor

The comparison of droptarget should look like source[0] !== droptarget[0] since both of them are jQuery Collection Objects.
An other of doing this would be by using the moved property (even though I don't prefer it and it might get deprecated).

@jegesh
Copy link

jegesh commented Mar 15, 2016

I'm sorry, maybe I'm dense, but I feel like you didn't read my last comment very closely. The problem I'm having is with the timing of the cancellation. If I cancel after I know if it's a reorder or a move, then the source list has already been updated, and cancelling producing the situation mentioned by the PO above, wherein the draggable is neither here nor there - it appears to be in the list, but it's missing from the sourceModel array. So I need to postpone the update until I know if it's a move or just a reorder, and then fire it, or decide not to.

@thgreasi
Copy link
Contributor

Please provide an example of your use case by forking one of the codepen
examples found in README and I will do my best to help you. If delayed
cancellation is all that you need, you can take a look at the "promised
cancellation" example.

Thodoris Greasidis
Computer, Networking &
Communications Engineer

@jegesh
Copy link

jegesh commented Mar 16, 2016

Thank you so much for your assistance. Examining the 'promised cancellation' example I was able to come up with a satisfactory workaround. I'm posting my code in case it might be of help to someone else in the future:

var _immovableItem = null;
$scope.sortableOptions.list1 = {
          connectWith:".list2",
          activate: function(){
            _immovableItem = null;
          },
          remove: function(e, ui){
            if (isInvalid(ui.item.sortable.model) {
              ui.item.sortable.cancel();
              _immovableItem = ui.item.sortable.model;
            }
          },
          stop: function(e, ui){
            if (_immovableItem) {
              ui.item.sortable.sourceModel.push(_immovableItem);
              $timeout(function(){
                $(e.target).find("li").last().remove();
              });
            }
          }
        };
        $scope.sortableOptions.list2 = {
          connectWith: ".list1",
          update: function (e, ui) {
            if(isInvalid(ui.item.sortable.model)){
              ui.item.sortable.cancel();
            }
          }
        };

Essentially, what's happening here is that in the first list, where I want to keep items that don't pass validation but allow them to be reordered within it, I perform validation on every update. If the item doesn't pass validation, I store it in the _immovableItem variable for later use. Then, if the item gets removed from that first list, I know the user is attempting to move it, which I don't want to allow, therefore I cancel the remove (which only prevents it from being removed from the DOM of the first list, but not the data model), cancel the update into the second list, and after everything has settled down (i.e. in a $timeout function), manually add the item back to the data model of the first list, and manually remove the orphaned <li> left over at the end of the list.

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

No branches or pull requests

4 participants