calling jQuery .remove() on custom UI widget cause

2019-08-05 07:26发布

问题:

I have created custom jQuery UI widget called uiPopover, very similar to UI-dialog (in fact, most of the code is copy-paste from it). This widget has a custom destroy method that hides the widget and removes it from the DOM. Again, it's pretty much copy-paste from UI-dialog.

    destroy: function() {
        var self = this;

        if (self.overlay) {
            self.overlay.destroy();
        }
        self.close();
        self.element
            .removeData('popover');
        self.uiPopover.remove();
        console.log('afterRemove')

        return self;
    },

The weird thing is that this causes an infinite loop that throws some errors:

$('#element').popover();
$('#element').remove();

As far as I can see, the problem is that when I call .remove(), it automatically calls destroy() on my widget (this is built-in in jQuery UI) and the destroy methodd tries to call remove() again on my element, and then that tries to call destroy() again and so on..

However, the weird thing is that this doesn't happen with UI dialog. So when I do this:

$('#element').dialog();
$('#element').remove();

Everything is okay... There must be something wrong with my plugin, but I cannot figure out what.

Here is the full source of my plugin: https://gist.github.com/2208569

回答1:

There's not much you can do about the recursive call to destroy(), aside from modifying jQuery UI itself. You can, however, break the chain by preventing remove() from being called again:

destroy: function() {
    var self = this;

    if (self.overlay) {
        self.overlay.destroy();
    }
    self.close();

    if (self.element.data("popover")) {
        self.element.removeData("popover");
        self.uiPopover.remove();
    }

    return self;
}

Note in passing that you don't have to copy and paste code in order to augment existing widgets, as the widget framework supports prototype inheritance. It would be interesting to know if your problem still occurs if you have your widget derive from $.ui.dialog instead of duplicating its code base.