Nestable
Nestable copied to clipboard
4 callbacks added
I added 4 callbacks: afterInit, onStartEvent, onMoveEvent and onEndEvent. Any chance we could add those callbacks?
Test code as follows.
$('#example-list-element').nestable({
afterInit: function ( event ) {
console.log( event );
}
})
.on('beforeDragStart', function(handle) {
console.log('dragStart', handle);
})
.on('dragStart', function(event, item, source) {
console.log('dragStart', event, item, source);
})
.on('dragMove', function(event, item, source, destination) {
console.log('dragMove', event, item, source);
})
.on('dragEnd', function(event, item, source, destination) {
console.log('dragEnd', event, item, source, destination);
})
.on('beforeDragEnd', function(event, item, source, destination, position, feedback) {
// If you need to persist list items order if changes, you need to comment the next line
if (source[0] === destination[0]) { feedback.abort = true; return; }
feedback.abort = !window.confirm('Continue?');
})
.on('dragEnd', function(event, item, source, destination, position) {
// Make an ajax request to persist move on database
// here you can pass item-id, source-id, destination-id and position index to the server
// ....
console.log('dragEnd', event, item, source, destination, position);
});
What you think about this solution instead?
var onEndEvent = function(e)
{
if (list.dragEl) {
e.preventDefault();
var item = list.dragEl.find('.'+list.options.itemClass);
list.dragRootEl.trigger('dragEnd', [
item, // List item
list.el, // Source list
list.dragRootEl // Destination list
]);
list.dragStop(e.touches ? e.touches[0] : e);
}
};
Usage:
$('.dd').nestable()
.on('dragEnd', function(event, item, source, destination) {
console.log(item, source, destination);
});
Thanks bigfoot, I do not really know the differences. Perhaps could you please tell me benefits of your solution? Thank you in advance!
By this way you can attach more than one listener on dragEnd
event.
You can also add or remove listeners at runtime.
The code listeners are decoupled from the list initialization, so you can also split your code in more files, for example 3rd party plugins. You can also create or remove lists at runtime, useful when you have a single page application.
I've also added three parameters because I need to know the list item I'm moving, and the source and destination lists.
This same method is also applicable to dragStart
and move
events.
bigfoot90, Thanks a lot for the detailed explanation! I have pushed the changes to the repo just as you kindly suggested.
Thank you. I made the changes
destination list from dragMove is back now.
Would be nice if the new position of the dragged element could be added to the dragEnd event arguments. Having this information, would simplify back-end handling/storage of the tree.
@webtweakers For position in destination you can use list.placeEl.index()
as fourth parameter in dragEnd
and move
events.
list.dragRootEl.trigger('dragEnd', [
item, // List item
list.el, // Source list
list.dragRootEl, // Destination list
list.placeEl.index() // Position
]);
@bigfoot90 Nice one, thanks.
@BeFiveINFO What is the state of this?
hello bigfoot90, thanks for checking up!
I just wanted to ask you about the timing where the trigger function should be at. Currently the trigger is called before "list.dragStop(e.touches ? e.touches[0] : e);" (ref: line 156) The action is not completed yet at the point of trigger to be precise. But placing the trigger for dragEnd right after dragStop let dragEl and dragRootEl inaccessible.
I wonder what we could do for this issue.
I am now thinking to place the trigger function right after the dragStop, then return just ID of the handle (as String) with the trigger. For example:
var onEndEvent = function(e)
{
if (list.dragEl) {
e.preventDefault();
var item_id = list.dragRootEl.find('li:first').data('id');
list.dragStop(e.touches ? e.touches[0] : e);
/* callback for dragEnd */
list.el.trigger('dragEnd',[item_id]);
}
};
Thank you for your advices in advance!
Placing the trigger after is right, but there is no way to prevent dragStop
.
Maybe split it into two eventsdragEnd
and beforeDragEnd
.
Currently I'm using this ugly workaround:
var onEndEvent = function(e)
{
if (!list.dragEl) return;
e.preventDefault();
var feedback = {abort: false};
var item = list.dragEl.find('.'+list.options.itemClass);
var sourceList = list.el;
var destinationList = list.dragRootEl;
var position = list.placeEl.index();
destinationList.trigger('beforeDragEnd', [
item, // List item
sourceList, // Source list
destinationList, // Destination list
position, // Position
feedback
]);
if (feedback.abort) return;
list.dragStop(e.touches ? e.touches[0] : e);
destinationList.trigger('dragEnd', [
item, // List item
sourceList, // Source list
destinationList, // Destination list
position // Position
]);
};
And use case:
$(this)
.nestable()
.on('beforeDragEnd', function(event, item, source, destination, position, feedback) {
if (source[0] === destination[0]) return;
feedback.abort = !window.confirm('Continue?');
})
.on('dragEnd', function(event, item, source, destination, position) {
if (source[0] === destination[0]) return;
// Make an ajax request to persist move on database
// here i need to pass item-id, source-id, destination-id, position index to the server
// ....
});
@BeFiveINFO What do you think?
Thanks @bigfoot90! I have made the changes just as you suggested.
Good ;-)
Just few questions/suggesstions:
- How you are using the event
dragJustBeforeStart
? - Rename
dragJustBeforeStart
tobeforeDragStart
to keep the same nomenclature, and also the shorter name is better. - The solution with
feedback
parameter is not good. I've made it only as a quick workaround. A better solution could be jQuery.Event, you can then check event.isPropagationStopped(). But currently I don't have time to work/test this. - Why you have renamed the script file? Maybe keeping the original name helps this PR to be merged in the future.
@bigfoot90 Thank you for the suggestions!
- How you are using the event dragJustBeforeStart? ** I use it to change the color of current item in the list
- Rename dragJustBeforeStart to beforeDragStart ** I agree. It makes more sense that way. I think that the name was from my random thought at that moment.
I will work on the issue below. I will post as soon as I have something to show.
- The solution with feedback parameter is not good.
I have noticed there are some minor errors in README.md
and in the first issue's post:
Corrected:
$('#example-list-element').nestable({
afterInit: function ( event ) {
console.log( event );
}
})
.on('beforeDragStart', function(handle) {
console.log('dragStart', handle);
})
.on('dragStart', function(event, item, source) {
console.log('dragStart', event, item, source);
})
.on('dragMove', function(event, item, source, destination) {
console.log('dragMove', event, item, source);
})
.on('dragEnd', function(event, item, source, destination) {
console.log('dragEnd', event, item, source, destination);
})
.on('beforeDragEnd', function(event, item, source, destination, position, feedback) {
// If you need to persist list items order if changes, you need to comment the next line
if (source[0] === destination[0]) { feedback.abort = true; return; }
feedback.abort = !window.confirm('Continue?');
})
.on('dragEnd', function(event, item, source, destination, position) {
// Make an ajax request to persist move on database
// here you can pass item-id, source-id, destination-id and position index to the server
// ....
console.log('dragEnd', event, item, source, destination, position);
});
Is there a clever way of canceling drop and return item to previous position ? something like this: .on('dragEnd', function(event, item, source, destination, position) { if(destination[0].id=='1337') { /* cancel working here, maybe this event.preventDefault(); return false; */ } }); but this not working. any ideas?
@Sysa Currently the feedback
method is the only that works. The script must be modified to use jQuery.Event.
@BeFiveINFO You have reverted your commit, What is the problem?
@bigfoot90 Please see : https://github.com/dbushell/Nestable/pull/143#discussion_r29993318
For what it is worth, I used your code to get the element and write it to the database. Here was what I used:
<?
if ($_REQUEST){
if ($_REQUEST['do'] == 'updatemenu'){
print_r($_REQUEST);
$dbicons = new SQLite3('./database/icons.sqlite');
$dbicons->busyTimeout(200);
$update = "UPDATE icons SET parent_id = :parent_id WHERE id = :id";
$stmt = $dbicons->prepare($update);
$stmt->bindParam(':parent_id', $_REQUEST["parent_id"]);
$stmt->bindParam(':id', $_REQUEST["id"]);
$stmt->execute();
if (!empty($_REQUEST['deletetask'])){
$id = $_REQUEST['deletetask'];
$delete = "DELETE FROM icons where id = :id";
$stmt = $db->prepare($delete);
$stmt->bindParam(':id', $id);
$stmt->execute();
}
$dbicons->close();
unset($dbicons);
};
}else{};
?>
Javascript:
$(".dd").on('dragEnd', function(event, item, source, destination, position) {
var currentItem = $(item).attr('data-id');
var itemParent = $(item).parent().parent().attr('data-id');
$.ajax({
method: "POST",
url: "iconadmin.php",
data: { id: currentItem, parent_id: itemParent, do: "updatemenu" }
})
.done(function( msg ) {
});
});```
+1 ;-)
+1 This new feature helped me a lot!
Would someone consider pushing the Merge button on this one? Two years and its still not merged? This is very helpful functionality.