Magnolia 5.7 reached extended end of life on May 31, 2022. Support for this branch is limited, see End-of-life policy. Please note that to cover the extra maintenance effort, this EEoL period is a paid extension in the life of the branch. Customers who opt for the extended maintenance will need a new license key to run future versions of Magnolia 5.7. If you have any questions or to subscribe to the extended maintenance, please get in touch with your local contact at Magnolia.
Magnolia uses the model-view-presenter pattern. The separation of views and presenters is done consistently throughout the application on server and client and within complex components. The presenter reacts on events raised by user interaction, driving the view by populating it with data to display.
UI events
Magnolia uses a model view presenter pattern to handle UI events.
- The View does not implement business logic or communicate with the Model. The view provides the interface to the end user and reacts on and informs the Presenter about user actions (input).
- The View and Presenter communicate together.
- The Presenter uses the Model to fetch data and implements business logic, informing the View to display content (such as a form).
- The View interface defines a Listener interface that is implemented by the Presenter. The purpose of the Listener interface is to ensure that the view does not inadvertently communicate to the Presenter.
- The Listener methods are implemented by the Presenter; the callback methods from the view to the Presenter.
- The
Presenter
only knows about theView
's Interface; this ensures that thePresenter
is not bypassing the pattern and cannot directly communicate to theView
implementation.
MVP and the app framework
Here we look at an example of how the MVP pattern is employed in a subapp.
- The View's interface defines an inline
Listener
interface with the methodgreetUser(String user)
.
public interface HelloWorldMainSubAppView extends View { void setListener(Listener listener); void addUser(String user); public interface Listener { void greetUser(String user); } }
2. The Presenter (subclass) implements:
View
inline listener interface and thegreetUser(String user)
callback method. The method is called by the View (via the listener) on user input through the UI.- The interface type of the View is determined by the
getView()
method. The Presenter
registers itself as theView
's Listener using theonSubAppStart()
method.- In the
onSubAppStart()
method thePresenter
calls theView
's interfacegetView().addUser("Lisa")
method.
//The Presenter implements the View's Listener by providing the View's callback method to the Presenter. public class HelloWorldMainSubApp extends BaseSubApp implements HelloWorldMainSubAppView.Listener { private LocationController locationController; // The View is injected into the Presenter's constructor. The View's implementation is defined by the IOC component provider. @Inject public HelloWorldMainSubApp(final SubAppContext subAppContext, HelloWorldMainSubAppView view, LocationController locationController) { super(subAppContext, view); // Set the location controller this.locationController = locationController; } // Defines the implementation of the injected view in use. @Override public HelloWorldMainSubAppView getView() { return (HelloWorldMainSubAppView) super.getView(); } @Override protected void onSubAppStart() { // Register this presenter as the View's Listener. getView().setListener(this); // Call the view to display something. getView().addUser("Lisa"); } // Implements the View's Listener method. Is the View's callback function to the presenter. @Override public void greetUser(String user) { // Do what ever logic needed triggered by this UI action. } }
View
calls the Presenter
via the Listener's
callback-function listener.greetUser(user):
@Override public void addUser(final String user) { Button button = new Button("Say hello to " + user + "!"); button.addClickListener(new Button.ClickListener() { @Override public void buttonClick(Button.ClickEvent event) { listener.greetUser(user); } }); layout.addComponent(button); }