MVP & dialog boxes

1,072 views
Skip to first unread message

Terry Bachard

unread,
Apr 7, 2011, 6:15:59 AM4/7/11
to google-we...@googlegroups.com
Hi,

I'm trying to adopt MVP as much as I can in my project (I'm using the 'do it yourself' way, not Activities and Places). However, sometimes it's hard to know what IS MVP and what isn't (I'm not writing tests yet, which doesn't help). My question is about dialog boxes...

Simple use case: There's a save button in my view (the view is called 'display' in presenter), that popups a cofirmation dialog box

Approach 1: If in my view, someone clicks "Save", then that button's click handler in my presenter might then call display.showConfirm(), which should return a boolean...it is a method in the view that'll create and display a popup dialog box, detect the Yes/No click (yes, detect in the view), and return the boolean to the presenter. Is that too much logic for the view to handle (i.e., creating dialog box, and displaying it, detecting the click and returning a boolean)?

Approach 2: Have a popup pre-instantiated (but hidden) in the view, assign click handlers to its buttons, in the presenter (there might be methods like Display.getYes(), Display.getNo() buttons). When user clicks Save, presenter will call display.showConfirm(), and then the view will show it. When user clicks Yes/No the button's click handlers in the presenter will then call display.closeConfirm() and the view will close it; then the presenter will either save or not save. To me this seems probably like the right approach in terms of MVP, but is overkill for what I think is essentially something that should belong totally in the view.

Approach 3: Alternatively, there could be a presenter/view for dialog boxes, but this also seems overkill for what is a very small problem!


Opinions? What approach would you take? It's a fairly dumb example but could help me in many more areas...



Regards,
Terra

Jens

unread,
Apr 7, 2011, 7:18:22 AM4/7/11
to google-we...@googlegroups.com
Well I also use the Mvp pattern (custom one) and in the beginning I always define methods HasXYZHandlers getXYZHandlerProvider() (e.g. HasClickHandler getSaveClickHandlerProvider() ) and use these in the presenter. So I would have chosen your second or even third approach.

But today I think it is better to perform simple tasks in the view itself and use as much code provided by GWT. So as we use UiBinder we are able to use the @UiHandler annotation which makes code much cleaner. Now our confirmation boxes for cancel and delete actions/buttons are implemented in the view itself and if the user wants to do an action the view calls a corresponding method defined by a delegate interface which is implemented by the view's presenter.

Example:

public interface MyPresenter extends Presenter {

  public interface MyPresentersView extends Display {

     public interface Delegate {
        public void doCancel();
        public void doDelete();
        /* basically one method for every user action/event */
     }

     /* should be the first method to be executed */
     public void setDelegate(MyPresentersView.Delegate delegate);

  }

}

public class MyPresentersViewImpl extends Composite implements MyPresentersView {

   /* UiBinder stuff */

   /* setDelegate method */

   private void ensureDelegate() {
     assert this.delegate != null : "Delegate not set";
   }

   @UiHandler("cancelButton")
   protected void onCancelClicked(ClickEvent e) {
     this.ensureDelegate();
     if(Window.confirm("Do you really want to cancel?")) {
       this.delegate.doCancel();
     }
   }

    /* other ui handler methods */
}


public class MyPresenterImpl implements MyPresenter, MyPresentersView.Delegate {

   /* implement doCancel() etc. */

}

I think this approach can also be done with dialog boxes although you need a bit more code in the view for handling the dialog box. As we use Window.confirm it is pretty simple. I like this pattern because the view knows a delegate interface that contains a method for every user action/event and can perform simple logic that do not have to be tested before calling a meaningful delegate method that performs more complicated logic. It also saves a lot of anonymous handler classes in the presenter.

Maybe you like this fourth approach ;-) But in general I would let the view perform some confirmation logic that do not have to be tested and let the presenter concentrate on complicated stuff.

J.

Terry Bachard

unread,
Apr 7, 2011, 8:14:05 AM4/7/11
to google-we...@googlegroups.com
Thanks Jen.

Yes, I can see how that works. Unfortunately I haven't implemented my MVP pattern this way so far, the view cannot delegate to the presenter; only the presenter can talk to the view...



Cheers,
Cormac

--
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.

Ben Imp

unread,
Apr 7, 2011, 9:26:00 AM4/7/11
to Google Web Toolkit
I've used approach #1 before (call a method on the view, it creates a
dialog) with good success. As long as it isn't complicated, that
works just fine, and I can't imagine it would be something significant
enough to require testing.

More recently, however, I've taken to Approach #3, whereby you have a
whole separate view/presenter for the dialog boxes. I go one extra
step and hide this behind a simple interface. I think this would work
a bit better for your implementation of the MVP pattern.

Snippet from inside one of my page presenters:

ChooseOneDialog<Suggestion> dialog =
this.bundle.getApplicationFactory().createChooseOneDialog();
dialog.addSelectionHandler(this.selectionHandler);
dialog.setOptions(ContactSuggestion.translate(result));
dialog.show();

The application factory is part of the resource bundle made available
to all of my presenters. The ChooseOneDialog interface hides the
implementation, but inside it is a fairly standard presenter/view.
The methods on the ChooseOneDialog interface simply delegate to the
presenter.

This allows me to keep this code separate and reusable, while at the
same time allowing me to mock it out for testing purposes, since both
the ApplicationFactory and the ChooseOneDialog are only known through
their interfaces. The bundle itself is actually a concrete class, but
all it does is contain interfaces, so it doesn't need mocking up.

-Ben

On Apr 7, 7:14 am, Terry Bachard <terram...@gmail.com> wrote:
> Thanks Jen.
>
> Yes, I can see how that works. Unfortunately I haven't implemented my MVP
> pattern this way so far, the view cannot delegate to the presenter; only the
> presenter can talk to the view...
>
> Cheers,
> Cormac
>

Terry Bachard

unread,
Apr 7, 2011, 10:08:17 AM4/7/11
to google-we...@googlegroups.com
Thanks for response. So you basically have a presenter invoking another presenter?

Currently, the only way I communicate with other presenters is via events; they know nothing of each other. But I suppose I could change that!


Cheers,
Terra

Ben Imp

unread,
Apr 7, 2011, 10:20:04 AM4/7/11
to Google Web Toolkit
Yeah, essentially. The one presenter doesn't know the details of what
lives behind that interface, which is the important bit.

I do have some 'child presenters' in the application as well. Those
are concrete presenter classes that a page presenter will instantiate
to handle some subset of functionality on the page. They have a
corresponding 'child view' interface on the page view that they are
assigned to handle. Those presenters aren't shared much, though, so I
don't think the lack of an obscuring interface matters as much.

this.revenueSplitPresenter = new
RevenueSplitComponentPresenter(bundle,
this.model.getRevenueSplitModel(), this.view.getRevenueSplitView());

You could also do something similar to this for the dialogs. The view
is still separate, so testing will still be fairly simple. However,
you do lose out on the ability to mock out that particular subset of
functionality, which may or may not matter.

-Ben

On Apr 7, 9:08 am, Terry Bachard <terram...@gmail.com> wrote:
> Thanks for response. So you basically have a presenter invoking another
> presenter?
>
> Currently, the only way I communicate with other presenters is via events;
> they know nothing of each other. But I suppose I could change that!
>
> Cheers,
> Terra
>
Reply all
Reply to author
Forward
0 new messages