GWT 2.0 UI BINDER MVP

94 views
Skip to first unread message

bond

unread,
Jan 22, 2010, 5:40:52 AM1/22/10
to Google Web Toolkit
Hi,
I read several articles about the mvp model in gwt. This guide is very
usefull: http://code.google.com/intl/it-IT/webtoolkit/doc/latest/tutorial/mvp-architecture.html.
But is not clear to me how to manage the Presenters with UiBinder.

For example if I've a tipical application with header,sidebar,content,
maybe I'll make at least 3 template (ui.xml).
So the App.ui.xml could be something as:

<g:DockLayoutPanel unit='PX'>
<g:north size='121'>
<my:Header></my:Header>
</g:north>
<g:center size="200">
<g:ScrollPanel>

<my:Content></my:Content>
</g:ScrollPanel>
</g:center>
</g:DockLayoutPanel>

where <my:Content> is another ui.xml template with the specific
content.
The entry point is:

public class Main implements EntryPoint {

@Override
public void onModuleLoad() {
ServiceAsync rpcService = GWT.create(Service.class);
HandlerManager eventBus = new HandlerManager(null);
AppController appViewer = new AppController(rpcService, eventBus);
appViewer.go(RootPanel.get());
}

}

But then if I add the Presenter of App.ui.xml only that presenter will
be binded to the view!! And the presenter/s of <my:Content> when(how)
can be binded?

Can you give me some suggestion or a basic structure of a generic
application with this pattern and uibinder?

Thanks

Best regards

Message has been deleted

Ahmet Recep Navruz

unread,
Jan 22, 2010, 4:40:12 PM1/22/10
to Google Web Toolkit
Waiting for the answer too :)

jarrod

unread,
Jan 24, 2010, 6:12:55 PM1/24/10
to Google Web Toolkit
From what I've read and done with MVP, you would generally implement
your View as two separate classes (HeaderView and HeaderPresenter).
Were that the case, your App.ui.xml wouldn't contain the actual views,
but rather placeholder slots for the children that the Presenter would
get from the child Presenters (HeaderPresenter, which has a
HeaderView, and ContentPresenter, which has a ContentView). You would
inject the HeaderPresenter and ContentPresenter into your
AppPresenter, which could then get and insert the child Views into
it's own slots.

It looks like, though, you're combining the Presenter and View roles
for your App, Header, and Content classes. That's not necessarily a
bad thing, but it means that your unit tests (you are unit testing,
right?) won't work in plain old JUnit... they'll have to use the
(slower) GWTTestCase harness, since they explicitly depend on
UiBinder, which won't work outside of a "development" mode.

Nonetheless, since you have combined them, I'll assume you are at
least using an MVP framework to help you? If you are using an MVP
framework like gwt-presenter or gwt-mvp, then the Presenter classes
have a bind() method (or something similar).

When one Presenter "contains" other presenters, as is the case here
for your AppController, then when it binds, it should take
responsibility for binding it's contained presenters at the right
time.

You'll need to use UiBinder to get references to your "child"
presenters. For the sake of this post, I will assume that, like
AppController below, your Header and Content classes also implement
both Presenter and View interfaces.

<g:DockLayoutPanel unit='PX'>
<g:north size='121'>

<my:Header ui:field="header" /> <!-- NB: ui:field -->


</g:north>
<g:center size="200">
<g:ScrollPanel>

<my:Content ui:field="content" /> <!-- NB: ui:field -->


</g:ScrollPanel>
</g:center>
</g:DockLayoutPanel>


In AppController, you'll have something like:

public class AppController implements Presenter, View {

interface Binder extends UiBinder<DockLayoutPanel, AppController> {}

private static Binder binder = GWT.create(Binder.class);

@UiField
Header header; // will be populated by UiBinder with your Header
// alternatively, you could set @UiField(provided=true) and use DI
// to get the instance of Header; pass it in as a constructor
arg ;-)

@UiField
Content content; // will be populated by UiBinder with your Content

ServiceAsync service;
HandlerManager eventBus;
DockLayoutPanel widget;

public AppControler(ServiceAsync service, HandlerManager eventBus) {
this.service = service;
this.eventBus = eventBus;
widget = binder.createAndBind(this);
}

@Override
public void bind() {
// when I bind you bind we bind!
header.bind();
content.bind();
}

@Override
public void unbind() {
header.unbind();
content.unbind();
}

// the remaining methods will vary,
// depending on your framework of choice

@Override
public void go(Panel panel) {
panel.add(widget);
}

@Override
public View getView() {
return this;
}

@Override
public Widget asWidget() {
return widget;

Stine Søndergaard

unread,
Jan 25, 2010, 4:16:00 AM1/25/10
to google-we...@googlegroups.com
... And how would the code example look if it was done the way you describe in your first paragraph?

jarrod

unread,
Jan 25, 2010, 12:32:48 PM1/25/10
to Google Web Toolkit
Were the HeaderView, HeaderPresenter, ContentView and ContentPresenter
split out accordingly, your AppPresenter might look something more
like this:

public class AppController implements Presenter, View {

interface Binder extends UiBinder<DockLayoutPanel, AppController>
{}

private static Binder binder = GWT.create(Binder.class);

@UiField(provided=true)
HeaderView header;

@UiField(provided=true)
ContentView content;

ServiceAsync service;

HandlerManager eventBus;

DockLayoutPanel widget;

public AppControler(ServiceAsync service, HandlerManager eventBus,
HeaderPresenter header, ContentPresenter presenter) {


this.service = service;
this.eventBus = eventBus;

this.header = header.getView();
this.content = content.getView();
widget = binder.createAndBind(this);
}

@Override
public void bind() {
// when I bind you bind we bind!
header.bind();
content.bind();
}
@Override
public void unbind() {
header.unbind();
content.unbind();
}

// the remaining methods will vary,
// depending on your framework of choice

@Override
public void go(Panel panel) {
panel.add(widget);
}

@Override
public View getView() {
return this;
}

@Override
public Widget asWidget() {
return widget;
}

}


This should work with the same App.ui.xml I previously posted above.

I should also note that I haven't specifically tested this code. It's
possible that the "View" classes will need to extend Widget to be
included in the UI by UiBinder. If that is the case, then the
following might be more appropriate:


<g:DockLayoutPanel unit='PX'>
<g:north size='121'>

<my:HeaderViewWidget ui:field="header" /> <!-- NB: ui:field -->


</g:north>
<g:center size="200">
<g:ScrollPanel>

<my:ContentViewWidget ui:field="content" /> <!-- NB: ui:field --


>
</g:ScrollPanel>
</g:center>
</g:DockLayoutPanel>

public class AppController implements Presenter, View {

interface Binder extends UiBinder<DockLayoutPanel, AppController>
{}

private static Binder binder = GWT.create(Binder.class);

@UiField(provided=true)
HeaderViewWidget header;

@UiField(provided=true)
ContentViewWidget content;

ServiceAsync service;

HandlerManager eventBus;

DockLayoutPanel widget;

public AppControler(ServiceAsync service, HandlerManager eventBus,
HeaderPresenter header, ContentPresenter presenter) {


this.service = service;
this.eventBus = eventBus;

this.header = header.getView().asWidget();
this.content = content.getView().asWidget();
widget = binder.createAndBind(this);
}

// the remainder is unchanged

jarrod

unread,
Jan 25, 2010, 12:35:21 PM1/25/10
to Google Web Toolkit
The constructors in the last post should have been as follows:

public AppControler(ServiceAsync service, HandlerManager eventBus,

HeaderPresenter header, ContentPresenter content) {


this.service = service;
this.eventBus = eventBus;
this.header = header.getView().asWidget();
this.content = content.getView().asWidget();
widget = binder.createAndBind(this);
}

I mistyped the name of the ContentPresenter argument...

Dalla

unread,
Jan 25, 2010, 11:50:39 PM1/25/10
to Google Web Toolkit
And what would you do, if the AppController does not contain both the
presenter and the view (which should be the case IMHO).
How would that code look?

Stine Søndergaard

unread,
Jan 26, 2010, 8:27:13 AM1/26/10
to google-we...@googlegroups.com
That is the question I felt like asking as well, Dalla.

Dalla

unread,
Jan 26, 2010, 10:46:22 AM1/26/10
to Google Web Toolkit
To clarify what I´m looking for, let´s assume that I´m working with
Googles MVP Contacts example.

Instead of having EditContactView and ContactsView as completly
separate views, I want to add them to a DockLayoutPanel,
showing both views at the same time.
Let´s assume that I want to put the ContactsView in the center panel,
and the EditContactView in the south panel.

I guess I would do this by creating a third view, called e.g. MainView
(and MainPresenter),
and then putting my existing views in this third view? But I´m still
confused as to how I would set this up,
or if creating a third view would even be the correct approach.

Please advice :-)

Dalla

unread,
Jan 27, 2010, 4:05:24 PM1/27/10
to Google Web Toolkit
If someone is interested, I solved this by injecting my child view
both into their respective presenters, aswell as into the parent view,
like so:


CouponWidget couponWidget = new CouponWidget();
GameStatsWidget gameStatsWidget = new GameStatsWidget();
CouponPresenter coupon = new CouponPresenter(rpcService,
eventBus, couponWidget);
GameStatsPresenter gameStats = new GameStatsPresenter
(rpcService, eventBus, gameStatsWidget);
presenter = new MainPresenter(rpcService, eventBus, coupon,
gameStats, new MainPanel(couponWidget,gameStatsWidget));

Coupon and Gamestats are child widgets here, they are injected into
their presenters as usual.
MainPresenter is the presenter responsible for the parent view,
MainPanel.

Beside this, I pretty much used code similar to the one suggested by
jarrod above.


On 26 Jan, 16:46, Dalla <dalla_man...@hotmail.com> wrote:
> To clarify what I´m looking for, let´s assume that I´m working with

> GooglesMVPContacts example.

Reply all
Reply to author
Forward
0 new messages