5
votes

If I am using the MVP pattern with GWT, as in the GWT architecture best practices talk from Google I/O from 2009, but have spread out the information into multiple widgets, how should the value object be populated?

Say I have a EditPersonView/Presenter, a EditPetView/Presenter and an EditAddressView/Presenter and the last two are widgets as a part of a panel in the EditPersonView. With these I have the following class:

class PersonDetails {
    private PetDetails pet;
    private AddressDetails addressDetails;

    // ...
}

The PetDetails and AddressDetails instance variables are managed in their presenter counterparts. When the user clicks the "Save" button in the EditPersonView, how should the communication between the widgets be done so that the PersonDetails is filled with information from its child widgets?

3

3 Answers

1
votes

I've faced this same problem in a few different GWT applications that I've designed using Ray Ryan's approach. My preferred solution is to create a Singleton "session object" that stores the state of that part of the application. In your example, it might look like this:

interface EditPersonSession {

    void fetchPerson(PersonId id);
    PersonDetails getCurrentPersonDetails();
    void updatePersonDetail(PersonDetail<?> detail);
    void updatePetDetail(PetDetail<?> detail);
    void updateAddressDetail(AddressDetail<?> detail);
    void save();

}

All three presenters contain a reference to the session object (perhaps injected by Gin). Whenever the UI (view) is manipulated by the user, the presenter associated with that view immediately pushes the state to the shared session object. For example, inside EditAddressPresenter:

view.getStreetNameTextBox().addValueChangeHandler(new ValueChangeHandler() {

    void onValueChange(ValueChangeEvent<String> event) {
        editPersonSession.updateAddressDetail(new StreetNameAddressDetail(event.getValue()));
    }

}

When it is time to save, the state object is told to save the state to the server. At this point, the session object has up-to-date representations of the data, and can save it all at once. So, in EditPersonPresenter:

view.getSaveButton().addClickHandler(new ClickHandler() {

    void onClick(ClickEvent event) {
        editPersonSession.save();
    }

}

This way, the presenters need not contain any references to each other, but can send consistent information to the server. If the presenters need to know when information that they display has been updated (either by other presenters, or by the server), the session object can notify them by firing events on the event bus (shared Singleton HandlerManager). The presenters can then pull the most current PersonDetails from the session object.

3
votes

If you look at page 42 of the presentation by Ray Ryan from Google IO 2009 you should find the solution to your question. You use an "event bus" (shared instance of HandlerManager) and fire your custom PetDetailsChangedEvent event and listen for that event from your child widgets (page 45). Also, remember that while decoupling, etc is great and all, some coupling is not a bad thing and might actually be a better solution than trying to force everything to be loosely coupled - RR says so in that presentation himself :)

0
votes

I've also come to the conclusion that I can have one model that corresponds to each presenter. So a PetWidget may create a Pet instance and a PersonWidget may create a Person instance. The PersonWidget may then contain one or more PetWidgets which in turn means that the Person class can have a list of Pet instances.