Tuesday, June 29, 2010

Re: MVP with EventBus question

I have totally restructured my app to follow the "page setup by event"
type idea that you've suggested in your email. I have been through all
four samples in the samples repo but can't answer my own question.

I have set up based on the "nested sample" but now I have a
HeaderPresenter like you have in your email, present on all pages,
Home, AboutUs, ContactUs. So essentially it's a singleton and will
never be removed/replaced.

Ok, now I see how you have this idea in your "leaf" presenters:
@Override
protected void revealInParent() {
RevealContentEvent.fire(eventBus, MainPresenter.TYPE_SetMainContent,
this);
}
... but now, what about the Header? I can't get it to be injected or
revealed. I'm not sure what the correct way is (maintaining loose
coupling). Currently I have:
@Override
protected void revealInParent() {
RevealContentEvent.fire(eventBus,
MainPresenter.TYPE_SetHeaderContent, this);
}
... in my HeaderPresenter, and then in my MainPagePresenter I have:
@ContentSlot
public static final Type<RevealContentHandler<?>> TYPE_SetMainContent
=
new Type<RevealContentHandler<?>>();

@ContentSlot
public static final Type<RevealContentHandler<?>>
TYPE_SetHeaderContent =
new Type<RevealContentHandler<?>>();

... and then in my MainPageView:

@Override
public void setContent(Object slot, Widget content) {
if (slot == MainPresenter.TYPE_SetMainContent) {
setMainContent(content);
} else if (slot == MainPresenter.TYPE_SetHeaderContent) {
setHeaderContent(content);
} else {
super.setContent(slot, content);
}
}

private void setHeaderContent(Widget content) {
mainHeaderPanel.clear();

if (content != null)
mainHeaderPanel.add(content);

}

private void setMainContent(Widget content) {
mainContentPanel.clear();

if (content != null)
mainContentPanel.add(content);
}

On Jun 28, 7:09 pm, Paul Schwarz <paulsschw...@gmail.com> wrote:
> Thanks so much for this answer. I have printed it and pinned it up
> right beside my screen so will be referring to it often until these
> concepts become solid in my mind. I think the largest mind gap here
> for me is the concept that a presenter's view is used to fill the
> whole screen, and then it has children presenter+view but the parent
> doesn't explicitly create or know about them!? I'm getting my head
> around these concepts slowly. Thanks for the info.
>
> Just a question for now though. An example really. Say you have an app
> with:
> - main screen
> - settings screen
>
> It also has a login panel that is essentially a singleton and popups
> up from time to time when your session expires, no presenter really
> owns it, it just lives in a void until your session expires.
>
> Now, your main screen should be accessible at /#main and your settings
> at /#settings.
>
> And lastly, your main page a header that is constantly present at the
> top of the page, but then in the main area it is like the "Expenses"
> example. i.e. it is a table of rows of data, but if you click on one
> of the rows it slides across to reveal more data for that row you
> clicked. So the main table would be available only at /#main, but
> then /#main;item=20 (or should it be /#item;id=20?) would slide across
> to reveal the details page for item 20. Then hitting /#main would
> slide you back to the main table.
>
> You can see from this example that there are a variety of Places, page
> states and widgets usages. Would you be so kind as to explain where
> you would apply Presenters, PresenterWidgets, etc and how you should
> handle the history tokens in order to give this app coherent "state"
> based on history, but optimal usage of GWTP in terms of correct MVP
> patterns (which then assist greatly with JUnit testing!).
>
> On Jun 27, 7:48 am, PhilBeaudoin <philippe.beaud...@gmail.com> wrote:
>
>
>
> > I answer to this earlier, but it somehow got gobbled by Google Groups.
> > If you see it around, let me know. ;)
>
> > Re: Complex widgets and PresenterWidgets
>
> > You're exactly right. PresenterWidgets are GWTP's way of doing a
> > complex widget with a nice testable class. Your PresenterWidget has
> > all the widget's logic and gets injected with the EventBus (and the
> > dispatcher if needed, or other services). The view is the complex
> > widget itself.
>
> > Re: Presenters vs PresenterWidget
>
> > Presenters are singletons. They are totally decoupled from one another
> > and communicate only via the Event bus. They can be organized
> > hierarchically, but the hierarchical structure is very loose: parent's
> > don't know their children in advance, and child don't know their
> > parent. The hierarchy gets sets up entirely via the EventBus. The
> > lowest-level Presenters of this hierarchy (so-called leaf Presenters)
> > need to be attached to a Place. They are (lazily) instanciated
> > whenever their history token is invoked, and at that point they set-up
> > the hierarchy.
>
> > PresenterWidget, on the other hand, are not singletons. Also, they are
> > meant to be injected in their parent Presenter (a bit like you would
> > expect complex widgets to contain one another). They are never
> > attached to a place: they get setup when their containing presenter is
> > set-up. Their parent presenter can communicate with them through
> > method invocation if desired, it does not have to use the event bus.
> > Really, PresenterWidget can be thought of as "widget with a testable
> > layer".
>
> > A typical complex page in a GWTP app might look something like:
>
> > PresenterA (splits the page in a header and a main area )
> > |
> > +-- HeaderPresenter
> > |
> > +-- MainContentPresenter
> >      |
> >      +--> ClientListPresenterWidget
> >           |
> >           +--> CliendDetailPopupPresenterWidget
>
> > Where:
> >  "--" denotes an indirect relationship (via the event bus)
> >  "-->" denotes an owned relationship (typically injected with GIN)
>
> > There are some examples of the sort on the gwt-platform website, you
> > may want to check them out.
>
> > Cheers,
>
> >    Philippe
>
> > On Jun 26, 4:08 am, Paul Schwarz <paulsschw...@gmail.com> wrote:
>
> > > Ok, I didn't implement it this way, but would prefer to.
>
> > > At the moment I have 3 mother-sized presenters + views. These have
> > > EventBus injected into them by gwt-platform. Then the widgets that are
> > > "owned" by this view are then constructed manually. I think I can
> > > still test them atomically but I'm not sure... the concepts are still
> > > a little hazy, learning UiBinder, Mocking and GWTP at the same time
> > > causes some head spin.
>
> > > My question now is when is it appropriate to make a new Presenter? and
> > > how does a PresenterWidget compare? I'm confused because in GWTP a
> > > presenter has a Place, so it seems like Presenters are "virtual" pages
> > > in an ajax app. But now you're saying to make Presenters for all my
> > > widgets individually... or is this where PresenterWidget comes in?
>
> > > At the moment things are scruffy because my presenter gets an EventBus
> > > injected, but then has to bubble it up through @UiFactory constructors
> > > into the owned Widgets.
>
> > > On Jun 24, 5:35 pm, PhilBeaudoin <philippe.beaud...@gmail.com> wrote:
>
> > > > In gwt-platform (http://code.google.com/p/gwt-platform/) we use gin to
> > > > inject the EventBus to whoever needs it. The framework is designed
> > > > such that only the presenters communicate on it.
>
> > > > In your example, the gwt-platform way would be to create a
> > > > PresenterWidget for WidgetA and another for WidgetB. This way they act
> > > > like widgets, but have a nice testable Presenter layer that can be
> > > > used to decouple interactions via the EventBus. If your custom
> > > > presenter for WidgetA has too many of these "addClickHandler" methods,
> > > > you can break things down further, getting an entire hierarchy of
> > > > PresenterWidget.
>
> > > > Hope it helps,
>
> > > >    Philippe
>
> > > > On Jun 23, 5:13 pm, Paul Schwarz <paulsschw...@gmail.com> wrote:
>
> > > > > I looked into that, and (unless I'm wrong), I think that
> > > > > @UiField(provided=true) will cause the UiBinder to look in the .ui.xml
> > > > > file for argument to satisfy Foo. In my case I am trying to "inject"
> > > > > an EventBus into the widget, not a visual element.
>
> > > > > On Jun 24, 2:18 am, Filipe Sousa <nat...@gmail.com> wrote:> I believe you can use @UiField(provided=true):
>
> > > > > > @UiField(provided=true)  Foo foo
>
> > > > > > @Inject
> > > > > > UserDashboard(Foo foo) {
> > > > > >   this.foo = foo
>
> > > > > > }
>
> > > > > > On Jun 23, 10:03 pm, Paul Schwarz <paulsschw...@gmail.com> wrote:
>
> > > > > > > To answer my own question:
>
> > > > > > > 1. Gin can be used to inject the EventBus into the View as well as the
> > > > > > > Presenter, so now our View has a reference to the EventBus
>
> > > > > > > 2. In order to give the EventBus to the Widgets "owned" by the View
> > > > > > > those Widgets will require a constructor argument which will be the
> > > > > > > EventBus instance. UiBinder will fail if it doesn't find a default
> > > > > > > constructor, except that they have provided some nice work arounds.
> > > > > > > The appropriate workaround in this case is to provide a widget
> > > > > > > factory. Notice the use of @UiFactory in the example below:
>
> > > > > > > public class UserDashboard extends Composite {
> > > > > > >   interface MyUiBinder extends UiBinder<Widget, UserDashboard>;
> > > > > > >   private static final MyUiBinder uiBinder =
> > > > > > > GWT.create(MyUiBinder.class);
>
> > > > > > >   private final String[] teamNames;
>
> > > > > > >   public UserDashboard(String... teamNames) {
> > > > > > >     this.teamNames = teamNames;
> > > > > > >     initWidget(uiBinder.createAndBindUi(this));
> > > > > > >   }
>
> > > > > > >   /** Used by MyUiBinder to instantiate CricketScores */
> > > > > > >   @UiFactory CricketScores makeCricketScores() { // method name is
> > > > > > > insignificant
> > > > > > >     return new CricketScores(teamNames);
> > > > > > >   }
>
> > > > > > > }
>
> > > > > > > On Jun 23, 11:04 pm, Paul Schwarz <paulsschw...@gmail.com> wrote:
>
> > > > > > > > Working with the MVP pattern, or more like the VP pattern at this
> > > > > > > > point, I have:
> > > > > > > > MainPagePresenter
> > > > > > > > MainPageView
> > > > > > > > WidgetA
> > > > > > > > WidgetB
>
> > > > > > > > ... so imagine that WidgetA and WidgetB will be attached to
> > > > > > > > MainPageView.
>
> > > > > > > > Using Gin I have an EventBus injected into the MainPagePresenter. I
> > > > > > > > can then add click handlers that place an event on the EventBus from
> > > > > > > > within my MainPagePresenter. This might look like:
>
> > > > > > > > getMainPageView().getSendButton().addClickHandler(new ClickHandler(){
> > > > > > > >   public void onClick(ClickEvent event) {
> > > > > > > >     eventBus.fireEvent(new SendEvent());
> > > > > > > >   }
>
> > > > > > > > }
>
> > > > > > > > But now let's say that WidgetA and WidgetB actually have quite a few
> > > > > > > > user interactions, you'll end up with a lot of methods that look like
> > > > > > > > the one above sitting in your Presenter class.
> > > > > > > > 1. Is this correct?
> > > > > > > > Or
> > > > > > > > 2. should the Presenter hand the reference to the EventBus through to
> > > > > > > > its View, who may even hand it through to the Widgets so that they can
> > > > > > > > talk directly to the EventBus?
>
> > > > > > > > If the second option is the better option from an architecture/
> > > > > > > > separation of concerns point of view, then what is the best way to
> > > > > > > > hand the reference over to the View in such a way that keeps the
> > > > > > > > coupling between Presenter and View as loose as possible?
>
> > > > > > > > Note, currently my Presenter defines a View interface which my View
> > > > > > > > implements, so the coupling is loose but...
>
> read more »

--
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-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to google-web-toolkit+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

No comments:

Post a Comment