dynamic value to uibinder in gwt

Cyclope picture Cyclope · Jul 15, 2012 · Viewed 7.4k times · Source

I am new to GWT and trying to making a page which is trying to inherit a composite widget but the value of the composite widget is dynamic.

My main page is somehting like:

         .....
         .....
         <g:Button>Open composite widget</g:button>
         .....
         .....

which is opening an another popup panel which is something like:

         .....
         <table>
            <tr><td>Top: <myCompany:userMeasurementUnit/> </td></tr>
            <tr><td>Bottom: <myCompany:userMeasurementUnit/> </td></tr>
            <tr><td>Left: <myCompany:userMeasurementUnit/> </td></tr>
            <tr><td>Right: <myCompany:userMeasurementUnit/> </td></tr>
        </table>

the above should show us

         top (cm)
         bottom (cm)
         left (cm)
         right (cm)

But I don't know how to pass the values from main page to custom widget i.e usermeasurementunit

          <myCompany:userMeasurementUnit/>

My usermeasurementunit is something like:

UIBinder:

     <htmlpanel tag="span" ui:field="unit"/>

and the composit widget is

      usermeasurementunit extends Composite {

       public usermeasurementunit(){
           initwidget...
       }

       public onload() { 
         ...
       }

       }

Now I want to pass any measurement unit cm or inches or meters upon clicking button. I tried it using the event bus but it didnt help because when I click the button popuppanel is not on the screen and its not catching the event. If any one of you can help me regarding this I would be really thankful as I am really struggling with this thing.

kind regards

Answer

Blessed Geek picture Blessed Geek · Jul 15, 2012

First of all, you need to understand the object instantiation flow in GWT.

They call it "delayed binding", not "dynamic binding".

Uibinder xml file is a layout template. And the JAva source bean behind it is known in general programming terms as the "code-behind".

The role or purpose of the uibinder layout template is to off-load the laying-out (on the internet many non-English speaking programmers write "lay-outing" which, though syntax-wise amusing, is the same thing) so that the code-behind could be focused on controlling the layout's responses.

It's akin to the MVP attitude. View implementation separated from presentation control. You can write the code-behind error free without even knowing exactly the positions where those fields are laid out. You could even simply supply a template where the ui elements are not properly laid out so as to concentrate on your code-behind first. Perhaps after that. one uibinder template for mobile while another for desktop - but they can share the same code-behind.

The values displayed effected by the uibinder template is determined once-and-for-all during uibind. There is no dynamic binding of a uibinder field to the ever changing value of an object/variable declared in the code-behind.

To dynamically change/propagate the values of a uibinder field after uibind, you have to deliberately set its value in the code-behind or write a listener to detect its change.

public class Graceland {

  @UiField
  Label pressure;

  @UiField
  Button reset;

  public void setPressure(int value) {
    pressure.setText(value);
  }

  @UiHandler("reset")
  void nameDoesNotMatter(ClickEvent ev) {
    pressure.setText(default);
  }
}

GWT.create() generates the Java source for the template during compile time. GWT.create is not a run-time function.

@UiField and @UiHandler are bound to the uifield in the template during uibind.

The role of uibind() is mostly not run-time but compile time too. Though, its finality is realised during run-time, all the javascript code and respective values to construct the objects are generated during compile time and executed once and only once during uibind at run-time.

Therefore, the intention is not to be able to completely replace the dynamic role of the code-behind but simply to free it from the task of laying-out, so that we the programmer could have a clean piece of code-behind being smudged as little as possible with the spaghetti source of the layout.

However, if you wish to "dynamically" affect the value of a uibinder field during bind time,then Ui:with is your friend.

package z.mambazo;
public class Graceland {
  ....
  String initialPressure(){
    /* "dynamically" obtain the pressure from the
     * pressure gauge in the petroleum distillation stack
     * during uibind
     */
  }
}

Graceland.ui.xml:

<ui:UiBinder blah...blah>
  <ui:with type="z.mambazo" field="zulu"/>
  <g:VerticalPanel>
    <g:Label
      ui:field="pressure"
      text="the temperature is :{zulu.initialPressure}"/>
  </g:VerticalPanel>
</ui:UiBinder>

The ui:with bean does not have to be the template's code-behind. Either the ui:with bean has an no-argument constructor or you have to supply ui:with tag with attributes corresponding to the constructor arguments.

You have to take note that in order to use ui:with, the init value must be declared in the value attribute not in the tag text.

<g:Label
  ui:field="pressure"
  text="the temperature is : {zulu.initialPressure}"/>

Not

<g:Label ui:field="pressure">
  the temperature is : {zulu.initialPressure}
</g:Label>

The second way, would simply reproduce the text as is.

However, you could also do it this way:

<g:HtmlPanel>
  the temperature is :&nbsp;
  <g:Label ui:field="pressure"
    text="{zulu.initialPressure}"/>
</g:HtmlPanel>

Also, be reminded that all GWT UI Java code, even the interim generated ones, are all translated into browser Javascript. So, whatever class you reference with ui:with must be in Java source code not Java byte code. And those source code must not at any time down the calling chain call byte code.