Reputation: 10714
I am using angular-drag-and-drop-lists (https://github.com/marceljuenemann/angular-drag-and-drop-lists) for my AngularJS project to create two lists that allow me to do the following:
Using a simple example on the library's site (http://marceljuenemann.github.io/angular-drag-and-drop-lists/demo/#/simple) I can see that these four conditions are easily achievable. However, things start to get hairy when I want to introduce slightly more complex behaviour:
I am largely adapting the sample code used in the example link provided above. The problem I am having is that the action I want to take place when moving items from list A to list B is also occurring when I reorder things in list A.
The current setup/pseudocode I have is the following:
My lists:
$scope.models.lists = {
"A": [],
"B": []
}
I populate these lists with information pulled from a database. Each item in the list also has a property that tracks how many children
the item has.
My markup looks like the following:
<ul dnd-list="list"
dnd-allowed-types="['itemType']"
dnd-drop="myCallback(event, index, item, external, type, 'itemType')">
<li ng-repeat="item in list | filter:searchText"
dnd-draggable="item"
dnd-moved="list.splice($index, 1)"
dnd-effect-allowed="move"
dnd-selected="models.selected = item"
dnd-type="'itemType'"
ng-class="{'selected': models.selected === item}"
ng-dblclick="editProperties();">
{{item.label + ' - ' + item.description}}
</li>
</ul>
My callback looks like the following:
$scope.myCallback= function(event, index, item, external, type, allowedType) {
// If the item in question has no children then we don't need to do anything special other than move the item.
if (item.children.length == 0) {
return item;
}
// If moving items around list B then just move them.
for (var i = 0; i < $scope.models.lists.B.length; i++) {
if (item.label === $scope.models.lists.B.[i].label) {
return item;
}
}
// I only want this code to execute if we know we are moving from list A to list B and the item in question has > 0 children.
if (item.children.length > 0) {
// Code that I want to execute only when moving from list A to list B goes here
}
If anyone is able to assist me with this I will be very grateful.
Thanks!
Upvotes: 2
Views: 4116
Reputation: 1
hi i have add a dragstartCallback that set variable in event.dataTransfer for the information of the origin/source of my dragged obj:
$scope.dragstartCallback = function(event){
var id = event.target.id;
var parent = $('#' + event.target.id).closest('ul')[0].id;
var group = $('#' + event.target.id).closest('div')[0].id;
event.dataTransfer.setData("id", id);
event.dataTransfer.setData("parent", parent);
event.dataTransfer.setData("group", group);
return true;
}
And in the dropCallback i just check if is List A or List B
$scope.dropCallback = function(event, index, item, external, type, allowedType) {
$scope.logListEvent('dropped at', event, index, external, type);
var idDivSource = event.dataTransfer.getData("parent");
var idDivDestination = $(event.target).closest('ul')[0].id;
var groupSource = event.dataTransfer.getData("group");
var groupDestination = $('#' + event.target.id).closest('div')[0].id;
if(groupSource == groupDestination){
if(idDivSource != idDivDestination){
if(idDivDestination == 'IDLISTB'){
return item?
}
if(idDivDestination == 'IDLISTA'){
DO Something else
}
DO Something else
}
}
}
Html code:
<div class="associated-drag-and-drop DnD" id="GROUP-MyD&D1" ng-repeat="(listName, list) in models.lists" flex="">
<ul dnd-list="list" id="{{listName}}" dnd-drop="dropCallback(event, index, item, external, type, 'containerType')" flex="">
<md-list-item class="associated-list__item" ng-repeat="item in list | filter:searchFilter" id="{{item.id}}"
dnd-dragover="dragoverCallback(event, index, external, type)"
dnd-dragstart="dragstartCallback(event)"
dnd-draggable="item"
dnd-moved="list.splice($index, 1)"
dnd-effect-allowed="move"
dnd-selected="models.selected = item"
ng-class="{'selected': models.selected === item}"
class="noright associated-list__item"
>
CONTENT
</md-list-item>
</ul>
</div>
Do not use this type of filter "| filter:searchFilter"
But use ng-show="And put here the condition"
Alternative change the reference to $index in dnd-moved="list.splice($index, 1)"
If you dont make this change you will have a problem with the filtered list when drag and drop
Exemple
NOT FILTERED LIST
you will have 2 array in 2 ng-repeat
ListA ListB
index1 of value index2 of value
ng-repeat of list ng-repeat of list
0 aaa 0 ppp
1 bbb 1 qqq
2 ccc 2 www
3 dddaaa 3 eeerrr
4 eeeccc 4 mmmwww
ecc... ecc...
The drag and drop lists work on the index of ng-repeat
FILTERED LIST
Now if we make a filter for 'a' with "| filter:searchFilter" code
angular will make this list
List A List B
0 aaa
1 dddaaa
the index when you drag "dddaaa" will be 1 and not 3
so it will not be removed from listA when dropped in listB
becouse the index is not the same as the non filtered list
instead if you use the ng-show="condition"
it will keep the original index of list not filtered
<md-list-item ng-repeat="item in list"
ng-show="condition">
</md-list-item>
My item list:
$scope.models = {
lists: {
"LISTA": [{1},{2},{3}],
"LISTB": [{1},{2},{3}]
}
};
Upvotes: 0
Reputation: 141
If you're not totally committed to that library (which, btw, doesn't work with a touchscreen) RubaXa's Sortable is the truth: Sortable
The documentation is strong, it's quite performant, and I wish I hadn't wasted my time on other DnD libraries before this one.
Upvotes: 2
Reputation: 1592
Looking at the README, the dnd-drop
event fires for any drop - regardless of whether it was within the same list or not.
Going by the script as you have it now, you need to check the event (or pass some additional information into your callback) to determine what list the event is firing on.
Upvotes: 2