public class MyPresenter implements SaveCancelHandler {
public interface Display {
public String getName();
public void setName(String name);
....
}
public void saveClicked(ClickEvent event) {
....
}
public void cancelClicked(ClickEvent event) {
....
}
}
public class MyPanel extends Composite implements MyPresenter.Display
{
@UiField TextBox nameBox;
@UiField Button saveButton;
@UiField Button cancelButton;
private SaveCancelHandler handler;
public void setSaveCancelHandler(SaveCancelHandler handler) {
this.handler = handler;
}
public void setName(String name) {
nameBox.setText(name);
}
public String getName() {
return nameBox.getText();
}
@UiHandler("saveButton")
public void saveClicked(ClickEvent event) {
handler.saveClicked(event);
}
@UiHandler()
public void cancelClicked(ClickEvent event) {
handler.cancelClicked(event);
}
}
// this could be a nested class, but this one seems really common:
public interface SaveCancelHandler {
public void saveClicked(ClickEvent event);
public void cancelClicked(ClickEvent event);
}
of course, this could be done with some more elegant events/handler
definitions etc and perhaps a nice HandlerManager so multiple Handlers
could be added to your display. This eliminates the anonymous class
definitions and leaves both your UI and Presenter with a rather clean
api. I'm playing around with this pattern now, so I don't know if
there is some pitfall waiting to bite me, but so far it's working well
and I like it *lots* better than this stuff:
getDisplay().addSaveHandler( new ClickHandler() {
public void onClick(ClickEvent event) {
saveClicked(event);
}
});
On Dec 15, 1:41 am, Jonas Huckestein <jonas.huckest...@me.com> wrote:
> > One question .. how does using @UiHandlerin the View code maintain
> > MVP? I would like to stick to @UiHandlerannotation, but it seems to
> > me that testing will get hurt. My current thinking is going with
> > something similar to what Thomas described above.
>
> I recall having read on the gin list a couple of months ago, that it
> might be useful to reverse the dependency of the view andpresenterin
> MVP. You could inject a "presenter" class into the class containing
> the @UiHandlerannotations and from the view call methods on thepresenter. I have to figure this out in the next couple of weeks since
> I am not yet sure about a lot of things. For instance, does thepresenterneed to know about the view class or can it be agnostic by
you could just do:
SaveCancelEvent event = new SaveCancelEvent();
eventBus.fireEvent(event);
of course this assumes you are fine with making event APIs for your
displays.
and you don't have to have your Display keeping track of instances of
listeners on it. That, and anyone can listen to your events,
although, usually I would think only your Presenter would be
listening.
cheers
-bryce
Thus, the View still fits the "humble object" definition, and the
Presenter is responsible for whatever gets done.
thanks!
-bryce
> --
>
> You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
> To post to this group, send email to google-we...@googlegroups.com.
> To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.
>
>
>
The ui.xml file contains a textbox, a couple of buttons, and a grid;
the relevant lines are:
<g:HTMLPanel>
<h1>CitiesUpdater</h1>
Start of City Name:
<g:TextBox u:field="cityNameStart"/>
<g:Button u:field="getCitiesButton" text="Get Cities"/>
<g:Button u:field="updateCitiesButton" text="Update Cities"/>
<hr />
<g:FlexTable u:field="cg"/>
</g:HTMLPanel>
The View includes:
@UiTemplate("CitiesUpdaterView.ui.xml")
interface Binder extends UiBinder<HTMLPanel, CitiesUpdaterView> {}
private static final Binder binder = GWT.create(Binder.class);
@UiField TextBox cityNameStart;
@UiField Button getCitiesButton;
@UiField Button updateCitiesButton;
@UiField FlexTable cg;
SimpleCallback<Object> onGetCitiesClickCallback;
SimpleCallback<Object> onUpdateCitiesClickCallback;
SimpleCallback<Object> onCityNameStartChangeCallback;
@Override
public void setOnCityNameStartChangeCallback(SimpleCallback<Object>
acb) {
onCityNameStartChangeCallback = acb;
}
@Override
public void setOnGetCitiesClickCallback(SimpleCallback<Object> acb)
{
onGetCitiesClickCallback = acb;
}
@Override
public void setOnUpdateCitiesClickCallback(SimpleCallback<Object>
acb) {
onUpdateCitiesClickCallback = acb;
}
@UiHandler("cityNameStart")
void uiOnChange(ChangeEvent event) {
onCityNameStartChangeCallback.onSuccess(null);
}
@UiHandler("getCitiesButton")
void uiOnGetClick(ClickEvent event) {
onGetCitiesClickCallback.onSuccess(null);
}
@UiHandler("updateCitiesButton")
void uiOnUpdateClick(ClickEvent event) {
onUpdateCitiesClickCallback.onSuccess(null);
}
The Presenter includes:
public CitiesUpdaterPresenter(
final String params, final CitiesUpdaterDisplay
citiesUpdaterDisplay,
final Environment environment) {
// ...
getDisplay().setOnGetCitiesClickCallback(new SimpleCallback<Object>
() {
// ...code to run, when the Get Cities button is clicked
});
getDisplay().setOnUpdateCitiesClickCallback(new
SimpleCallback<Object>() {
// ...code to run when the Update button is clicked
});
getDisplay().setOnCityNameStartChangeCallback(new
SimpleCallback<Object>() {
//...code to run whenever the CityNameStart field changes
}
So...
* the Presenter is injected with the Display (View) to use
* the Presenter injects three callbacks into the View
* the View uses @UiHandler to define three handlers
* the handlers just call the callbacks that were set by the Presenter
Note that SimpleCallback is an extension of AsyncCallback.
I hope this is clearer; I deleted as much code as possible, to make
the example simpler. Please ask again if you have any doubts or
questions.
Best regards,
F.Kereki
and rather have simple member methods be invoked like:
public void onCityNameStartFieldChange() {
....
}
that gets directly invoked by the View.
I'm kinda getting sick of writing anonymous classes.
The approach you are suggesting is quite similar to just making
anonymous ClickHanders or ValueChangeHandler instances.
I'd much rather define higher level events.
So, if I had a view that had a few fields:
@UiField Button saveButton;
@UiField Button cancelButton;
@UiField Button addEmailButton;
I'd like to have some relevant api defined for ui events that is
business logic agnostic, so something like this:
public interface BeanHandler {
public void saveClicked();
public void cancelClicked();
public void emailAdded();
}
etc. perhaps these methods could have parameters, like some event
that had contextual data (like what view class fired the event), but
basically this boils down to this:
@UiHandler("saveButton")
public void onSaveClicked(ClickEvent event) {
beanHandler.saveClicked();
}
@UiHandler("cancelButton")
public void onCancelClicked(ClickEvent event) {
beanHandler.cancelClicked();
}
@UiHandler("addEmailButton")
public void onAddEmailClicked(ClickEvent event) {
beanHandler.emailAdded();
}
and of course, beanHandler is just some instance of an interface that
gets injected via a setter or something.
then your presenter turns into this:
public class BeanPresenter implments BeanHandler {
..... business logic methods...
// BeanHandler methods:
public void saveClicked() {
someService.save(myBean);
}
public void cancelClicked() {
getDisplay().reset();
}
public void emailAdded() {
String email = getDisplay().getEmailValue();
myBean.addEmail(email);
}
}
this accomplishes the same things you itemize above, it's just that
you don't have to deal with boiler plate anonymous classes that
(usually) invoke the same kinds of methods I just defined, usually you
have something like this:
ClickHandler handler = new ClickHandler() {
public void onClick(ClickEvent event) {
saveClicked();
}
}
public void saveClicked() {
....
}
I'm leaning towards any approach that cuts out the boiler plate code
above. In essence, your approach and what I have in mind do the same
thing, I just want to avoid the anonymous classes :)
thanks!
-bryce
In the same way that the View implements Display, an interface defined
in the Presenter class, Presenter could implement Execute, an
interface defined in the View class.
The View should have a method allowing injection of the Execute
object; the Presenter would this "self injection" in its constructor.
Then, whenever any event happened, the View handler would do getExecute
( ).someMethod( ).
You would do away with all anonymous classes, and each class (View,
Presenter) would implement an interface defined in the other class.
The symmetry breaks down a bit because you cannot inject each object
in the other through their constructors (obviously!)
Is this along the lines you were thinking?
You are correct on the constructor injection though, you wouldn't be
able to inject both via constructor arguments, however, in the
Presenter constructor you could simply inject it's self into a setter
on the Display:
public MyPresenter(MyDisplay display) {
display.setExecute(this);
}
I'm used to Spring-style injection, which usually leverages some kind
of setter post-construction anyhow. You could even have some other
class implement the Executer api that just had a reference to the
Presenter instance, but that's a few levels of indirection for
delegating method calls :)
I guess it's a small trade off for me to self-inject in my constructor
rather than having Guice inject me if I can reduce boiler plate code.
I'm glad to hear you were at least considering my approach, it's nice
to know i'm not way off in left field.
-bryce
http://www.resmarksystems.com/code/GwtSample.zip
It's pretty basic, and some things could be improved (like the use of
GIN/Guice and some more reflection based RPC dispatching on the
server), but I didn't go to great lengths to include that because the
main thing I wanted to demonstrate in this code was the use of the MVC
tweaks brought up in this thread.
I want to emphasize that it was thrown together for a friend in order
to demonstrate concepts and not as a tutorial walk through, it
includes stuff like rpc based login (which I don't suggest using).
Anyhow, I hope it helps demonstrate how I'm dispatching events.
as far as your using UiBinder + MVP without any issues: I wouldn't say
your "missing" anything per se', it's just that I wanted something
cleaner than what I was seeing around the forums. I don't like
returning HasText/HasClickHandler type interfaces from my view to my
presenter 'cause I think my display can be smarter than that without
embedding any business logic in it. I like making calls like
display.getName() rather than display.getNameBox().getText(). When I
do things that way, it makes it really easy to swap out my display
instances with simple beans and I don't have to much with any testing
frameworks like easymock or anything. I've found it to be helpful.
cheers,
-bryce
I have been wrestling with this design pattern the past week or so on
my application architecture. I am eagerly awaiting to hear Google's
stance on UiBinder + MVP patterns but maybe we'll have to wait for I/O
to find that out :)
In the meantime I really appreciated this thread and I've gone with
something very much along the lines of what Bryce mentioned with
having the 'Execute' interface in the Presenter. Having the 'Execute'
interface defined in the View seemed too circular for me (and also the
javac) :)
Here's my code:
---------------------------------------------
Presenter
---------------------------------------------
public class MyPresenter implements Presenter {
public interface DisplayHandlers {
void onBackLabelClicked();
}
public interface Display {
void setDisplayHandlers(DisplayHandlers handlers);
Widget asWidget();
}
public MyPresenter(..., HandlerManager eventBus,
Display display) {
this.eventBus = eventBus;
this.display = display;
}
@Override
public Widget bind() {
display.setDisplayHandlers(new DisplayHandlers() {
@Override
public void onBackLabelClicked() {
// fire an event on the bus or whatever else you may fancy
}
});
return display.asWidget();
}
}
---------------------------------------------
View
---------------------------------------------
public class ErrorView extends Composite implements
ErrorPresenter.Display {
@UiField
Label backLabel;
ErrorPresenter.DisplayHandlers handlers;
}
---------------------------------------------
hope this helps someone (only relevant code is shown)
> > 2010/1/29 István Szoboszlai <mrsz...@gmail.com>
>
> >> Hello Bryce,
>
> >> Are you using the approach you were describing in any project now with
> >> success? If so it would be very appreciated if you could write some
> >> sentences about your experiences.
> >> I thing I like what you proposed, and I also think it is not a big
> >> drawback that you have to inject the presenters 'execute' interface int he
> >> view by hand.
>
> >> So I think I will give a chance to this approach.
>
> >> I'll write if I have any conclusion (good, or bad).
>
> >> Best - Istvan
>
> >> istvan.szobosz...@inepex.com | +36 30 432 8533 | inepex.com
---------------------------------------------
View
---------------------------------------------
public class MyView extends Composite implements MyPresenter.Display {
@UiField
Label backLabel;
MyPresenter.DisplayHandlers handlers;
@UiHandler("backLabel")
void handleBackClick(ClickEvent e) {
handlers.onBackLabelClicked();
}
@Override
public void setDisplayHandlers(MyPresenter.DisplayHandlers handlers)
{
this.handlers = handlers;
}
}
---------------------------------------------
addHandler(...);
fireEvent(myEvent);
so, if your DisplayHandlers interface extends Presenter, and you have
a simple Event that extends GwtEvent, then you have a really handy way
of tracking listeners (i.e. you don't have to track them, the
GwtFramework does). that, and you can avoid any nested classes that
have inline implementations.... just a thought.
thanks for the post!!
best regards,
-bryce
On Feb 21, 11:33 am, ross <ross.m.sm...@googlemail.com> wrote:
> Hey all,
>
> I have been wrestling with this design pattern the past week or so on
> my application architecture. I am eagerly awaiting to hear Google's
> stance onUiBinder+MVPpatterns but maybe we'll have to wait for I/O
> > as far as your usingUiBinder+MVPwithout any issues: I wouldn't say
> > your "missing" anything per se', it's just that I wanted something
> > cleaner than what I was seeing around the forums. I don't like
> > returning HasText/HasClickHandler type interfaces from my view to my
> > presenter 'cause I think my display can be smarter than that without
> > embedding any business logic in it. I like making calls like
> > display.getName() rather than display.getNameBox().getText(). When I
> > do things that way, it makes it really easy to swap out my display
> > instances with simple beans and I don't have to much with any testing
> > frameworks like easymock or anything. I've found it to be helpful.
>
> > cheers,
> > -bryce
>
> > On Fri, Jan 29, 2010 at 3:42 AM, Matt Read <mr...@spotd.co.uk> wrote:
> > > Hi, could you possible re-cap on what problem this approach solves? I'm
> > > usingUIBinderwithmvp-presenter without inverting the dependencies in this
The first time I played with UiBinder I was quite tempted to put raw
event handling in the view's .java file, however it felt wrong
(especially after watching Ray Ryans GWT Best Practices talk), so that
drove me to having the view dispatch events rather than control the
UI's business logic. For instance: sometimes you need to pull things
from the backend server based on an event from the user (choosing
something from a drop down, clicking on a checkbox etc.) it just feels
wrong to have a class that extends Composite handle that kind of
traffic. Hence the decision to have a Presenter manage that
communication.
History has shown when you have a clear, distinct separation of
concerns between your UI and your business logic your code is more
stable, note that this isn't a clear line drawn between the UI event
handling and the UI layout. :)
I guess it all boils down to preference, but I do happen to have
experience working on projects where business logic is embedded in
display level classes and it simply isn't scalable (i.e. you can't
swap out the display easily, and you can't ever re-use the business
logic code unless you load your whole UI framework).
just a thought,
-bryce