سؤال

I'm writing a jQuery UI plugin. Inside that plugin, when an action occurs, I'm invoking one of the plugin options as a callback. Once that callback is completed, I want to run some cleanup code.

To be more specific, my plugin uses jQuery UI draggable and droppable. On droppable drop, I invoke a function defined in the options called update. After update is called, which is an AJAX call, I want to perform some cleanup. I don't want the user of the plugin to be required to perform this cleanup call; I want the cleanup call to happen automatically after the update AJAX method is successful.

I thought using jQuery's Deferred made sense here. Here's some code for the plugin's drop implementation:

self.connectedLists = $(self.options.connectWith)
    .not(self.list)
    .droppable({
        hoverClass: 'ui-selectablelist-active',
        drop: function(e, ui) {
            var sender = $(ui.draggable).closest('ul'),
                deferred = self.options.update.call(self, e, {
                    sender: sender,
                    receiver: $(this),
                    items: selectedItems
                });

            deferred.then(function () {
                self.removeSelectedItems();
            });
        }
    });

And the code for the plugin implementer looks like this:

update: function (e, ui) {
    var self = this;
    return $.post(url, 
            {                 
                // some data                         
            })
            .done(function (data) {
                console.log('updated!');
            });
}

I'm returning the AJAX call as a promise to the drop callback. Inside the drop callback, I want to perform the cleanup operation removeSelectedItems always, so I use the .then() function. It doesn't seem to be running.

Does this pattern sound like a good idea. Can anyone help me with this design? Why isn't my done function running inside the drop callback?

هل كانت مفيدة؟

المحلول

Instead of using .then, use .always.

.then is used for adding callbacks to a deferred object:

deferred.then(donecallbacks,failcallbacks)

Try:

self.connectedLists = $(self.options.connectWith)
    .not(self.list)
    .droppable({
        hoverClass: 'ui-selectablelist-active',
        drop: function(e, ui) {
            var sender = $(ui.draggable).closest('ul'),
                deferred = self.options.update.call(self, e, {
                    sender: sender,
                    receiver: $(this),
                    items: selectedItems
                });

            deferred.always(function () {
                self.removeSelectedItems();
            });
        }
    });

Update:

Since the developer will be specifying the update function, there's always a possibility of the developer not properly returning the deferred object to you. You should check for that and throw an exceiption in that case.

self.connectedLists = $(self.options.connectWith)
    .not(self.list)
    .droppable({
        hoverClass: 'ui-selectablelist-active',
        drop: function(e, ui) {
            var sender = $(ui.draggable).closest('ul'),
                deferred = self.options.update.call(self, e, {
                    sender: sender,
                    receiver: $(this),
                    items: selectedItems
                });
            if (deferred.always) {
                deferred.always(function () {
                  self.removeSelectedItems();
                });
            }
            else {
                $.error("Update must return a deferred object.");
            }
        }
    });
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top