On Apr 1, 1:15 am, Nathan Wells <[email protected]> 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([email protected]())) 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. -- You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.
