Search code examples
javajquery-uigwtjsni

GWT JQueryUI Dialog wrapper not "attaching widget"


I have written a simple class that wraps the JQUeryUI Dialog. It basically looks like this:

public class Dialog extends Composite
{
    final String id;

    public Dialog(IsWidget body) {
            initWidget(body.asWidget());
            id = DOM.createUniqueId();
            getElement().setId(id);
    }

    public void create() {
            create(id);
    }

    public void open() {
            open(id);
    }

    final native void create(String id) /*-{
            $wnd.jQuery("#" + id).dialog({ autoHide: true });
    }-*/;

    final native void open(String id) /*-{
            $wnd.jQuery("#" + id).dialog("open");
    }-*/;
}

I pass the initialized view (i'm using a uibinder template). It works fine when the view only contains simple HTML elements such as check-boxes, but when it contains complex widgets like a disclosure panel or cell lists - the panels fail to respond to click events. The disclosure panel does not open and the cell lists don't respond to events either although both these views worked fine before when they were housed in a "GWT popup panel".

Update

Here is more source code that shows how the Dialog is initialized.

HasDialog parent = (HasDialog) body;
Dialog dialog = parent.getDialog();
dialog.open();

FYI HasDialog is just an interface inherited by the widget.

interface HasDialog { Dialog getDialog(); }

For example, the widget that contains the disclosure panel widgets looks like this:

final Dialog dialog;

@Override
public Dialog getDialog()
{
    if (dialog == null) {  // only one instance
        dialog = new Dialog(this);
        dialog.create();
    }

    // dialog buttons and events have been commented out

    return dialog;
}

We can assume there is not an internal problem with the widget because it works fine when used with the GWT Popup Panel:

PopupPanel popup = new PopupPanel();
popup.setWidget(body);
popup.center();

I agree with logan and I think the onAttach or onLoad events are being sunk for the views child widgets. I notice these methods are protected. What would be the right away to go about wiring these properly?

Update 2

I've narrowed down the problem being that the widget (passed through the constructor) is not being attached to the DOM - as far as the widget itself is concerned.

public void open()
{
    open(id);
    if (getWidget().isAttached() == false) {
        Window.alert("Widget not attached");
    }
}

I believe the Widget Javadoc provides some relevant information to my situation.

protected void doAttachChildren()

If a widget contains one or more child widgets that are not in the logical widget hierarchy (the child is physically connected only on the DOM level), it must override this method and call onAttach() for each of its child widgets.

Given that the Dialog class should be able to work on with any widget, I do not want to down cast my widget and start writing lots of boilerplate, surely there must be a way to elegantly attach the widget. Ideas?


Solution

  • Modify your open method:

        public void open() {
            onAttach();
            RootPanel.detachOnWindowClose(this);
            open(id);
        }
    

    add on close handler:

        void onClose() {
            if(RootPanel.isInDetachList(this)) {
                RootPanel.detachNow(this);
            }
            else {
                onDetach();
            }
        }
    

    register onclose handler while creating dialog:

        final native void create(String id) /*-{
            var _self = this;
            $wnd.jQuery("#" + id).dialog({ 
                autoHide: true, 
                close: function(event, ui) {
                    [email protected]::onClose()();
                    _self = null;
                }
            });
        }-*/;
    

    And let the rest stay untouched ;)

    EDIT: in fact you even do not have to generate DomNode's id as you can instantiate Jquery object directly on DomNode. Your whole class after modifications:

    public class Dialog extends Composite {
    
        public Dialog(IsWidget body) {
            initWidget(body.asWidget());
        }
    
        public void create() {
            create(getElement());
        }
    
        public void open() {
            onAttach();
            RootPanel.detachOnWindowClose(this);
            open(getElement());
        }
    
        void onClose() {
            if(RootPanel.isInDetachList(this)) {
                RootPanel.detachNow(this);
            }
            else {
                onDetach();
            }
        }
    
        final native void create(Element element) /*-{
            var _self = this;
            $wnd.jQuery(element).dialog({ 
                autoHide: true, 
                close: function(event, ui) {
                    [email protected]::onClose()();
                    _self = null;
                }
            });
        }-*/;
    
        final native void open(Element element) /*-{
            $wnd.jQuery(element).dialog("open");
        }-*/;
    }