How to combine multiple widgets based on uiBinder?

I need to insert [number] of ujBinder widgets in another, in a specific place. The widget you entered has a somewhat complicated layout, so I'm trying to define it in HTML.

referencePanel.add (...) does not work with java.lang.IllegalStateException: the parent of this widget does not implement HasWidgets. I don’t know which widget the parent is unhappy with - innerPanel or referencePanel.

If the ReferenceUI object is added to the RootPanel, then it is added at the bottom of the page. But if he first adds a RootPanel, then when added to the referencePanel there is JavaScriptException 3 (HIERARCHY_REQUEST_ERR) code.

Any suggestions?

public class AppUIDemo extends Composite { @UiTemplate("AppUIDemo.ui.xml") interface AppUIDemoUiBinder extends UiBinder<Widget, AppUIDemo> { } @UiTemplate("ReferenceUI.ui.xml") interface ReferenceUIUiBinder extends UiBinder<Widget, ReferenceUI> { } private static AppUIDemoUiBinder uiBinder = GWT .create(AppUIDemoUiBinder.class); private static ReferenceUIUiBinder refUIBinder = GWT .create(ReferenceUIUiBinder.class); @UiField FlowPanel referencePanel; public AppUIDemo() { initWidget(uiBinder.createAndBindUi(this)); ReferenceUI reference = new ReferenceUI(refUIBinder); HTMLPanel innerPanel = reference.getRefPanel(); innerPanel.getElement().setId(HTMLPanel.createUniqueId()); referencePanel.add(innerPanel); } } 

 public class ReferenceUI extends Composite { interface ReferenceUIUiBinder extends UiBinder<Widget,ReferenceUI> { } private static ReferenceUIUiBinder uiBinder = GWT .create(ReferenceUIUiBinder.class); @UiField HTMLPanel refPanel; public ReferenceUI() { initWidget(uiBinder.createAndBindUi(this)); } public CreditReferenceUI(final UiBinder<Widget, CreditReferenceUI> binder) { initWidget(binder.createAndBindUi(this)); } public HTMLPanel getRefPanel() { return refPanel; } } 

ReferenceUI.ui.xml

 <!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent"> <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:gwittir="urn:import:com.totsp.gwittir.client.ui"> <g:HTMLPanel ui:field="referencePanel"> <table> <tr> <td> <b>First Name</b></td> <td> <b>Last Name</b></td> <td> <b>Phone</b></td> <td> <b>Fax</b></td> </tr> <tr> <td> <gwittir:TextBox ui:field="referenceFirstName" styleName="input"/></td> <td> <gwittir:TextBox ui:field="referenceLastName" styleName="input"/></td> <td> <table><tr> <td> ( </td> <td> <gwittir:TextBox ui:field="referencePhoneAreaCode" styleName="input" maxLength="3"/></td> <td> ) </td> <td> <gwittir:TextBox ui:field="referencePhoneNumber" styleName="input" maxLength="7"/></td> <td> # </td> <td> <gwittir:TextBox ui:field="referencePhoneExtension" styleName="input" maxLength="25"/></td> </tr></table></td> <td> <table><tr> <td> ( </td> <td> <gwittir:TextBox ui:field="referenceFaxAreaCode" styleName="input" maxLength="3"/></td> <td> ) </td> <td> <gwittir:TextBox ui:field="referenceFaxNumber" styleName="input" maxLength="7"/></td> </tr></table></td> </tr> <tr> <td style="text-align:right"> <b>Address: </b> Street</td> <td> <gwittir:TextBox ui:field="referenceStreet" styleName="input"/></td> <td colspan="2" style="width:50%"> <table><tr><td> City</td> <td><gwittir:TextBox ui:field="referenceCity" styleName="input" maxLength="25"/></td> <td> State </td> <td class="state"><gwittir:TextBox ui:field="referenceState" styleName="input" maxLength="2"/></td> <td> ZIP</td> <td><gwittir:TextBox ui:field="referenceZIP" styleName="input" maxLength="9"/></td></tr></table> </td> </tr> </table> </g:HTMLPanel> </ui:UiBinder> 

AppUIDemo.ui.xml

 <!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent"> <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:gwittir="urn:import:com.totsp.gwittir.client.ui"> <g:HTMLPanel ui:field="basePanel"> <!-- <div id="MainContent"> --> <p><h2><b>Application Demo</b></h2></p> <g:FlowPanel ui:field="referencePanel"> </g:FlowPanel> </g:HTMLPanel> </ui:UiBinder> 
+6
java xml gwt widget uibinder
source share
2 answers

I will start with the correction, then move on to explain later.

Problem fix

The easiest way to fix this problem is as follows. Here is your code:

 HTMLPanel innerPanel = reference.getRefPanel(); innerPanel.getElement().setId(HTMLPanel.createUniqueId()); referencePanel.add(innerPanel); 

Replace this with the following code. Note that only the last line has changed.

 HTMLPanel innerPanel = reference.getRefPanel(); innerPanel.getElement().setId(HTMLPanel.createUniqueId()); referencePanel.add(reference); 

This way you add a Composite object. There will be no difference to the user, as the HTMLPanel (your innerPanel ) will be directly attached to the document.


Some background

Adding a widget to a complex panel

When you add a widget to a complex panel (a panel containing more than one child widget), four things happen one after another:

  • The widget is prompted to remove itself from the current parent
  • The panel adds the widget to the list of its children
  • The panel adds a widget to the document
  • The widget is asked to set the panel as its new parent

Specifying a widget to remove from the parent

When a child is asked to remove himself from his parent, one of the following events will occur:

  • If the widget does not have a parent, it does nothing
  • If the widget is a child of the panel that implements HasWidgets , the widget tells the panel to remove this widget.
  • Otherwise, the widget throws an IllegalStateException with the message "This widget parent does not implement HasWidgets

Compound widgets

When initWidget(Widget) called, the initWidget(Widget) parent is set to the Composite object.

Problem

When you try to add an innerPanel , it will be asked to remove itself from the current parent. innerPanel is actually the root of your UiBinder template. Its parent object is Composite (specifically, ReferenceUI ). An exception is thrown because Composite does not implement HasWidgets and does not support deleting its widget.

+13
source share

Unfortunately, IIRC you cannot set the id for the widget in the UiBinder code (I think you can only use regular HTML). Thus, you are left with setting the correct identifier using someWidget.getElement().setId() (as in the code above).

What is missing now, I think, is a placeholder (div, span, whatever) with the correct id in the HTMLPanel referencePanel , for example:

 <g:HTMLPanel ui:field="referencePanel"> <div ui:field="referencePanelInner" /> </g:HTMLPanel> 

And in AppUIDemo :

 @UiField DivElement referencePanelInner; // ... public AppUIDemo() { // ... referencePanelInner.setId(reference.getRefPanelId()); } 

... if you do not want to add the ReferenceUI directly to the referencePanel - in this case you just need to use the FlowPanel :)

PS: IMHO, you must generate and set a unique identifier for ReferenceUI.refPanel from the ReferenceUI class (and expose the identifier) ​​- this way you will not interact with the "inside" widgets from some external widgets.


Ok, I think I get it. An IllegalStateException thrown because you add a ReferenceUI.refPanel (or ReferenceUI.referencePanel , I don't know what the current name is) on AppUIDemo ( ReferenceUI obviously does not implement HasWidgets ) - when you have to add the entire composition of the ReferenceUI reference :) I don’t know why you did this in the first place (perhaps due to all the mess with identifiers), but the code should look something like this:

 public AppUIDemo() { initWidget(uiBinder.createAndBindUi(this)); ReferenceUI reference = new ReferenceUI(refUIBinder); referencePanel.add(reference); } 
+3
source share

All Articles