Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dynamic value to uibinder in gwt

Tags:

gwt

uibinder

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

like image 825
Cyclope Avatar asked Jul 14 '12 23:07

Cyclope


2 Answers

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.

like image 173
Blessed Geek Avatar answered Sep 19 '22 16:09

Blessed Geek


What you need are shared resources. Here is an example:

MeasurementConstants.java:

package com.acme.client;

public class MeasurementConstants {

    private final String measurementUnit;

    public MeasurementConstants(String measurementUnit) {
        this.measurementUnit = measurementUnit;
    }

    public String measurementUnit() {
        return measurementUnit;
    }

}

UiBinderMeasurement.java:

package com.acme.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;

public class UiBinderMeasurement extends Composite {

    private static UiBinderI18nUiBinder uiBinder = GWT
            .create(UiBinderI18nUiBinder.class);
    private MeasurementConstants constants;

    interface UiBinderI18nUiBinder extends UiBinder<Widget, UiBinderMeasurement> {
    }

    public UiBinderMeasurement(MeasurementConstants constants) {
        this.constants = constants;
        initWidget(uiBinder.createAndBindUi(this));
    }

    @UiFactory
    public MeasurementConstants getConstants() {
        return constants;
    }

}

UiBinderMeasurement.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">

    <ui:with type="com.acme.client.MeasurementConstants" field="constants"></ui:with>

    <g:HTMLPanel>
        <table>
            <tr><td><g:Label text="Top ({constants.measurementUnit}):" /> </td></tr>
            <tr><td><g:Label text="Bottom ({constants.measurementUnit}):" /> </td></tr>
            <tr><td><g:Label text="Left ({constants.measurementUnit}):" /> </td></tr>
            <tr><td><g:Label text="Right ({constants.measurementUnit}):" /> </td></tr>
        </table>
    </g:HTMLPanel>
</ui:UiBinder>

Now you can call it like this:

new UiBinderMeasurement(new MeasurementConstants("cm"))
like image 32
Steffen Schäfer Avatar answered Sep 20 '22 16:09

Steffen Schäfer