Would the MenuItem class need to implement HasClickHandler so that
when a MenuItem is clicked, the action can be handled in the
presenter. At this time, the MenuItem needs an object that implements
the Command interface, so the view seems to know about the presenter.
I would like to know what others think about this.
- mic.
Theoretically, you could just make inner classes in a Presenter for
each Command you write. It all depends on how you want to organize
your code and the needs of your specific project.
I've recently migrated from views with many HasXxxHandlers getters to
views with a setListener method that the presenter "injects" into its
view. The listener defines "callback methods" such as save(), close(),
italicize(), bold(), delete(), etc.
It makes unit tests waaay easier to write (you don't have to mock each
HasXxxHandlers, capturing each added XxxHandler, eventually mocking
the XxxEvent, etc.) and in your case would make things easier: the
Command is an implementation detail of the view.
I've heard of your approach before, but I'm not clear on the
implementation... are you passing the presenter itself into the view?
or are you passing instances of event handlers? The difference seems
trivial, but in practice (as I imagine it, anyway) seems large:
http://etherpad.com/sIAaiCfuiG
Let me know what you think. I would assume the first way is what your
referring to in your comment above, which implies that it is a View
layer responsibility to deal with HandlerRegistrations and the like.
Is that correct?
--
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.
On Apr 1, 1:15 am, Nathan Wells <nwwe...@gmail.com> wrote:
> Thomas,
>
> I've heard of your approach before, but I'm not clear on the
> implementation... are you passing the presenter itself into the view?
> or are you passing instances of event handlers? The difference seems
> trivial, but in practice (as I imagine it, anyway) seems large:
>
> http://etherpad.com/sIAaiCfuiG
>
> Let me know what you think. I would assume the first way is what your
> referring to in your comment above, which implies that it is a View
> layer responsibility to deal with HandlerRegistrations and the like.
> Is that correct?
Yes. It makes a few things much easier for me:
- I can use @UiHandler in the view, which makes the whole thing more
readable (on the down-side, I used to create a class that implement
all required handlers instead of using an anonymous class per handler;
UiBinder doesn't do this optimization (yet?) with @UiHandlers)
- I can use event delegation in the view
- The view methods are more "consistent" (get/setUserName and
setUserNameEnabled(boolean), vs. getUserName->get/setText and
setUserNameEnabled(boolean); this elad people to ask for a HasEnable
interface, which wouldn't solve anything as you'd still need
getUserName->HasText and getUserNameEnablable->HasEnable), even more
when also dealing with non-widget UI elements: I implemented a login
form with a <form> in the HTML page which action="" is set to callback
a GWT method ($wnd.__form_callback = $entry(view.@....onSubmit())) and
had to create a dummy HasClickHandlers to return as the
"HasClickHandlers submitButton()"; with a Listener is way easier: the
onSubmit just calls back the listener.submit().
- I have one "screen" where the user can add files to upload, each
"file" is a line composed of a FileUpload and a "cancel" button next
to it that removes the "line" from the screen (and therefore "cancels
the file" before the form is submitted), already uploaded files
(unpredictable number) are shown as a label with a "delete" button
next to it. Add to this that files are grouped into dynamic,
unpredictable "groups". Previously, I did everything with a
SelectionEvent<String> where the value was something like "add:<file
group>", "cancel:<file id>", or "delete:<file id>" (I use event
delegation in the view). Now, instead of firing a SelectionEvent with
a specific value, I just call the listener's addFile(String group),
cancelFile(String fileId) or deleteFile(String fileId).
Sure I could have defined new events instead of doing it all through a
SelectionEvent but it wouldn't have make things much easier, with more
files to maintain.
As for the implementation, I currently have something like:
public class FooPresenter {
@ImplementedBy(FooView.class)
public interface Display {
void setListener(Listener listener);
void setThisVisible(boolean visible);
void setThatEnabled(boolean enabled);
}
public interface Listener {
void save();
void close();
}
private class Handlers implements PlaceHandler,
SomeOtherBusEventHandler, Listener {
...
}
@Inject
public FooPresenter(Display view, EventBus bus) {
Handlers handlers = new Handlers();
bus.addHandler(PlaceEvent.getType(), handlers);
bus.addHandler(SomeOtherBusEvent.getType(), handlers);
view.setListener(handlers);
}
...
}
public class FooView implements FooPresenter.Display {
@UiField Button save;
@UiField Button close;
private FooPresenter.Listener listener;
...
public void setListener(FooPresenter.Listener listener) {
assert listener != null;
this.listener = listener;
}
@UiHandler("close")
void onCloseClick(ClickEvent event) {
listener.close();
}
@UiHandler("save")
void onSaveClick(ClickEvent event) {
listener.save();
}
}
I'm using a Listener *interface* so the view doesn't have direct
dependencies on the presenter's behavior (I could therefore mock a
Listener and make a small app to "manually test" my view without
actually having any presenter, event bus, etc.)
I decided to switch to this design instead of HasXxxHandlers when I
saw Ray's work on RequestFactory: """In the Wave style: the view
(editor) has a single listener for its semantic operations."""
The main difference is that I do not have an interface for each
presenter with its impl class (interface FooPresenter / class
FooPresenterImpl implements FooPresenter, FooPresenter.Listener) so my
presenter class doesn't itself implement the listener interface (it
would also "pollute" its public API, which is not a problem in Ray's
case where no other object has a direct dependency on the Impl class,
only on the presenter interface).
In a new project we're starting, I might reconsider this approach
though, and introduce an interface vs. impl class dichotomy all over
the place.
Something to be aware of though: the Listener approach puts a bit more
responsibility into the view than the HasXxxHandlers approach, but
it's so much easier to work with (and write unit tests) that's I think
it's worth it.
I think it does not clearly separate out the View and Presenter using
interfaces. This is the reason why I moved away from using menus.
I would prefer if there was a HasMenuItemClicked which returns the
menu item and the presenter would have code like
this.display.getABCMenuItem().addClickHandler() ( new ClickHandler() {
public void onClick(MenuItemClickEvent event) {
doAction();
}
});
I think this is much cleaner...
mic
On Mar 31, 5:05 am, Nathan Wells <nwwe...@gmail.com> wrote:
> I created an "EventFiringCommand" class for instances like this.
> Basically, you put the event bus and the event to fire (or the code to
> generate the event) in the command. The Command should be a presenter-
> layer object, since it has no need to know about the view (and should
> be easy to unit test).
>
> Theoretically, you could just make inner classes in a Presenter for
> each Command you write. It all depends on how you want to organize
> your code and the needs of your specific project.
>
I feel the Google IO MVP approach is good because interfaces are used
to abstract the interaction between view and presenter. IMHO, the view
containing the presenter or the presenter knowing about the view makes
replacing presenters and views extremely difficult especially if you
do want to target desktop and mobile apps.
-mic
> > google-web-tool...@googlegroups.com<google-web-toolkit%2Bunsu...@googlegroups.com>
I need to think more about this approach. Ray mentioned in his talk
about having too many events and performance. Does your approach not
lead to that?
-mic