Using UiBinder with mvp4g produced two instances of my widget

I am currently getting up to speed with GWT, so I am experiencing many growing pains if you will.  This one stumped me for awhile, so I thought I would share.

The application I am creating is one that would display a Person (fields: name, birthdate) and his Address (fields: line1, line2, city, state, postalCode).  I am using GWT 2.3, mvp4g 1.4 and also using UiBinder and Editors.

Here is the main widget that is added to the RootPanel.

<!--  -->
<!--  MainView.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:sw="urn:import:com.stevewall.contactorganizer.client.view">
    <g:HTMLPanel>
        <div>
            <h1>Simple Bean Person</h1>
            <sw:PersonSimpleEditor/>
        </div>  
    </g:HTMLPanel>
</ui:UiBinder>

Also, here is the Presenter associated with PersonSimpleEditor:

@Presenter(view = PersonSimpleEditor.class)
public class PersonSimplePresenter extends BasePresenter<PersonSimpleEditor, AppEventBus>{
    public void onPersonSimpleChanged(PersonSimple person) {
        getView().updateDisplay(person);
    }
}

As I mentioned above, I am using Editors.  The method onPersonSimpleChanged() above is invoked by my mvp4g EventBus when a new Person has been retrieved from the server.  The call to getView().updateDisplay(person) will invoke SimpleBeanEditorDriver.edit(person), which should have automatically updated my UI widgets with the values in the PersonSimple object.

However, this didn’t work.

I started debugging and I stumbled upon the fact that I my PersonSimpleEditor constructor was being invoked twice.  Why???

The first call was because it is declared in my MainView.ui.xml file.

The second call was because it is the view declared in the mvp4g @Presenter annotation for the PersonSimplePresenter class.

I discovered that it was the second one that was the one the Presenter was using (obviously, since that was the one associated with the Presenter).  However, that instance was never added to the MainView widget (only the one declared in the ui.xml file is actually added to the MainView widget).  So I needed to remove the first one from MainView.ui.xml since that instance was not being used by the Presenter, and then I also needed to make sure the Presenter’s instance was added to the MainView widget.

And then everything worked!

Here is my final code:

<!--  -->
<!--  MainView.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">
    <g:HTMLPanel>
        <div>
            <h1>Simple Bean Person</h1>
            <g:SimplePanel ui:field="personContainer"/>
        </div>  
    </g:HTMLPanel>
</ui:UiBinder>

And the Presenter too:

@Presenter(view = PersonSimpleEditor.class)
public class PersonSimplePresenter extends BasePresenter<PersonSimpleEditor, AppEventBus>{

    public void onPersonSimpleChanged(PersonSimple person) {
        getView().updateDisplay(person);
        getEventBus().displaySimplePerson(getView());
    }
}

The last line that uses the event bus will take the view (e.g. the PersonSimpleEditor instance) and do personConstainer.setWidget(personView) with the PersonSimpleEditor instance.

Advertisements

About stevewall123

I am a Lead Software Engineer in Minneapolis working for Thomson Reuters. I am currently working on projects using Java, JavaScript, Spring, Drools, Hazelcast, Liquibase and Tomcat. Previously, I used C#, GWT, Grails, Groovy, JMS and JBoss Drools Guvnor. In the past I have worked on projects using J2EE, Swing, Webwork, Hibernate, Spring, Spring-WS, JMS, JUnit and Ant.
This entry was posted in Editors, GWT, Mvp4g, UiBinder and tagged , , , . Bookmark the permalink.

3 Responses to Using UiBinder with mvp4g produced two instances of my widget

  1. Pierre says:

    You don’t have to call getEventBus().displaySimplePerson(getView()); all the times but you can use GIN to manage nested view. You can set the view as singleton and inject it to your main view. This way, the same instance will be used by the presenter and the main view:

    //mark the view as singleton
    @Singleton
    public class PersonSimpleEditor …

    //inject it to the main view thanks to GIN
    public class MainView … {
    @UiField(provided=true)
    PersonSimpleEditor personEditor;
    @Inject
    public MainView(PersonSimpleEditor personEditor){
    this.personEditor = personEditor;

    }
    }

  2. stevewall123 says:

    Excellent tip Pierre. Thanks! I tried what you suggested and it worked great. That allowed me to declare my PersonSimpleEditor in my UiBinder file.

  3. Hi Steve,

    Nice blog! Is there an email address I can contact you in private?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s