I am writing a web application using GWT, and following the MVP tutorial on the GWT website (i.e. using History for navigation).
I am a bit confused as to the best way of having a side-bar for navigation (i.e. clicking a navigation link changes content in main window. See below)
--------------------
| | |
| nav | main |
| | window |
| | |
| | |
--------------------
One potential way I see of doing this is to declare two <div> tags in the HTML for navigation and content. For example:
#Override
public void onValueChange(ValueChangeEvent<String> event) {
...
if (token.equals("navigation")) {
presenter = new NavigationPresenter(rpcService, eventBus, new NavigationView());
presenter.go(RootPanel.get("navigation"));
}
...
if (token.equals("content")) {
presenter = new ContentPresenter(rpcService, eventBus, new ContentView());
presenter.go(RootPanel.get("content"));
}
...
}
I am unsure if this is the best way of approaching this. (I guess bi-directional communication between the navigation panel and the content window could be done through an EventBus? Is this method flexible when it comes to changing the UI (e.g. for mobile sites))
I was wondering what people would suggest is the best way of going about this. I have read around and often land on discussions about Activities and Places, but as I understand it these are somewhat different to MVP architecture (activities and places is useful for browser history management, although I think my use of History covers that (?))
Any suggestions would be appreciated.
Yes, you are right: Activies and Places are about history and navigation management, a framework inside GWT. MVP is simply an architectural design pattern. You can achieve MVP using such framework as shown in the article you linked.
In your sample, you can do as you say, but I'd make each view a (lazy) singleton in order to avoid any potentially expensive re-creation. Personally I don't like this way, you end up defining your Displays in terms of (so many) HasXxx interfaces.
I think that if history management is important, choosing Activities and Places is almost a no-brainer (at least for me, and at least to define the skeleton of the app). Here you can find a really good article to get you started. And you will see how common your use case is: you have to define displayed regions (you navigation and main areas) that will react (thanks to the activity managers) on place change and create/restart the activities that will in turn update the UI. This way you achieve some sort of app-wide MVP in which the presenters are the activities.
As far as MVP is concerned, there is no best way of doing that: part 1, part 2 and MVP with A&P are simply different ways to achieve the same goal: separation between presentation and business logic, as well as pure junit testing. Simply choose what you like. See this post on groups for reference.
Hope that get you started.
For my apps, I use a ClientFactory just like in the GWT doc, with singleton for Views.
That way, the application structure (which includes the menu) is also a singleton referenced in the ClientFactory, so every other view can virtually access it directly through its interface.
For example some view might push some image in the header, hide the menu to display a video, or whatever you need. Most of the time, the app's structure does not need a separate activity/place to "persist" its state in the history stack...
I know most people don't like to have views calling each other, and so do I, the only exception is the app's structure view, which is kind of a specific one : it has a presenter which is not an activity, and the view itself is permanently displayed.
Communicating between your app structure and other views with notifications will make your app a spaghetti bowl IMHO. I have worked with frameworks like PureMVC which rely a lot on events/notifications to communicate between view, and the separation has a steep cost : maintainability and code readability.
Related
I am trying to make a web app with GWT and I am trying to use the MVP design pattern. It looks like an Activity is pretty much the same as a Presenter but a presenter is more specific to a certain view, which means a Presenter should knows the special methods/elements the view supports.
But there are two options to do the same thing.
a) Let Presenter extends an Activity with additioanl methods needed by the view.
b) Let presenter and activity hold a reference to each other. In this case, the activity will do generic operations and presenter will do view specific operations.
Could anyone please help point out which option is more viable? Thanks!
As always with architectural design decision: it depends.
I'd recommend starting simple, where the activity is the presenter; i.e. one class plays both the role of an activity (driven by the activity manager) and the presenter (that drives the view).
And if the need arises, split them. Either to obtain smaller more maintainable classes, or because you start having different lifetimes (in GWT's mobilewebapp sample, the TaskActivity lives longer than the presenters, and can switch between 2 presenters during its lifetime).
The rule of thumb is that activities are for navigation, and you can switch between several tasks without necessarily navigating (where each task would have a bookmarkable URL). In the case of the modilewebapp sample, switching between viewing and editing a task does not navigate between them.
Having separate activities and presenters also means that you could have different ways of navigating in different apps, sharing the same presenters but not the same activities (note: activities are already about that kind of dychotomy, but there are times where it doesn't really match, such as whether you consider switching between viewing and editing a navigation between "pages" or just switching task in the same "page").
My app (written using MvvmCross and with MVVM pattern in mind) needs to display popup windows where user can choose of confirm certain options. So basically it's a classic modal dialog, but since the app's view model is implemented in a portable class library, it needs to tackle modality in a generalized sense - some platforms simply don't have exact match for a modal dialog.
There are a few threads discussing dialogs in MVVM (Open dialog in WPF MVVM, WPF MVVM dialog example). Following their advices I could probably solve this by introducing DialogService and implementing it for each platform. However I will be treating then dialogs like other services - storage service, map service etc.. But a dialog is a part of the presentation concept, so I wonder if it can be treated more like a view, so instead of calling an instance of an obscure IDialogService I could navigate to it using an MVVM framework of my choice (MvvmCross in my case).
I checked MvvmCross implementation and samples but found almost no dialog-related stuff.
Within MvvmCross, the presenter is responsible for how Views/ViewModels are shown when using ShowViewModel.
This presenter is a view/UI level object - it's ultimately the UIs job to decide if a view should be shown as a page, as a control, in a tab, in a split-view, as a dialog, etc.
v3 does introduce a presentation hint that the ViewModel can help suggest how the View should be shown - but it's up to the presenter on each platform to determine how (if) to use this hint.
Alternatively, Dialogs/flyouts/etc can easily be shown using MvxMessenger messages from ViewModel to View with a little bit of code behind.
For 'modality', also consider Greg's post on 'returning results' - see http://www.gregshackles.com/2012/11/returning-results-from-view-models-in-mvvmcross/
We've been using the recommended GWT approach of building parts of our application in an MVP manner. The logic we use is based on Google's examples - the Presenter fetches/prepares data and sets it on the View, and the View contains a reference to the Presenter which it calls (e.g. in UiHandlers).
Some parts of the application which we built should be reused in other views. For example - a view which is sometimes the "main view" of a part of the application - can be used inside a pop-up in another part of the application (of course, the views/presenters are initialized differently in this other case, but basically it is the same thing).
What would be the correct approach to do stuff like this? I cannot seem to find a suitable one without resorting to ugly hacky stuff.
For example - if I put the presenter of the reused component inside the main view - it is easy to initialize the reused component, but it is ugly to receive a result back in the main presenter. This can be solved by passing a runnable or creating a custom handler or passing the parent presenter itself to the reused presenter.
All of these approaches don't seem right to me though and seem ugly.
Any ideas/experiences?
What you're describing is a view being able to be controlled by 2 distinct presenters. Abstracting those presenters behind a common API, in the form of an interface, should be enough.
You can also see it as a composite widget being used within two distinct views. The composite widget would then expose events and a public API that both views could wire to their specific presenters.
See Activites and Places,It can help you to desing and structure you app.
https://developers.google.com/web-toolkit/doc/latest/DevGuideMvpActivitiesAndPlaces
.
This question already has an answer here:
GWT 2.1 Places example without Activities
(1 answer)
Closed 3 years ago.
On an existing project we’re using MVP (hand crafted) reasonably well. It’s understood and does mostly what we need. For a new project I'm looking at using the MVP framework built into GWT 2.1 (Activities and Places).
Our applications are mostly tabbed displays with each tab bound to a single view widget.
I’ve tried to use Activities and Places without success for this type of display. Part of the problem is that the example Hello World article ended up leaving me chasing my tail, too many new concepts for my brain to digest.
The Hello World sample IMO is not a sufficient introduction and doesn’t deal with many of the real world use cases. I was hoping someone could point me in the direction of any sample applications that use MVP for tabbed displays. Thomas Broyer has some excellent posts on his blog but these have still left me a little perplexed.
Previously I’ve used an AppController to handle tabs changes and single presenters for each tab. The new architecture in GWT 2.1 leaves me more confused that it should.
I'm using the gwt Activities/Places framework for a tabbed display, and it works great, BUT: I decided to abandon the TabLayoutPanel widget we had been using and create my own navbar (that looks like tabs) and a content pane. The effect is the same - it looks identical - but the implementation is much cleaner.
I think the problem is in trying to mix Activities/Places, which has its own idea of navigation, with a TabPanel, which has another idea of navigation. At first I tried to throw them together, overriding tab button behavior to trigger a PlaceController, which in turn switched the tabs around, but... it was messy. With the independent navbar / content pane, the PlaceController could do everything just like it wanted to. You just have to manually switch the views, instead of letting a TabPanel do it for you.
I also faced this problem but managed to make it work using one activity per Tab and each activity using a presenter (or more) to display the components of the tab.
Regarding the solution found by Riley Lark, I, instead, opted by using a Decorator pattern and, so, keep the original TabbedPanel. How ? Each activity gets injected (GIN) a presenter that contains a decorator for the TabbedPanel.
So, for example:
Tab1Activity gets injected with Tab1Presenter, which, in turn, gets injected with Tab1Decorator which decorates the TabbedPanel with a Tab1ContentPanel (this panel contains all the widgets to be displayed on the Tab1 tab)
Tab2Activity gets injected with Tab2Presenter, which, in turn, gets injected with Tab2Decorator which decorates the same TabbedPanel with a Tab2ContentPanel (this panel contains all the widgets to be displayed on the Tab2 tab)
Seems complex but, after creating the first decorator, it really paid off and I was able to keep the TabbedPanel and take advantage of the URL history management implicit in the framework.
I'm a beginner with Eclipse RCP and I'm trying to build an application for myself to give it a go. I'm confused about how one actually goes about handling model objects. None of the examples I can find deal with the problem I'm having, so I suspect I'm going about it the wrong way.
Say I need to initialise the application with a class that holds authenticated user info. I used my WorkbenchWindowAdvisor (wrong place?) to perform some initialisation (e.g. authentication) to decide what view to show. Once that's done, a view is shown. Now, that view also needs access to the user info I had earlier retrieved/produced.
The question is, how is that view supposed to get that data? The view is wired up in the plugin.xml. I don't see any way I can give the data to the view. So I assume the view has to retrieve it somehow. But what's the proper place for it to retrieve it from? I thought of putting static variables in the IApplication implementation, but that felt wrong. Any advice or pointers much appreciated. Thanks.
The problem you are facing here is in my opinion not RCP related. Its more an architectural problem. Your view is wired with business logicand!
The solution can be done by two (common) design-patterns:
Model-View-Controler (MVC)
Model-View-Presenter (MVP)
You can find plenty information about this in the web. I am going to point a possible solution for your particular problem using MVP.
You will need to create several projects. One is of course an RCP plugin, lets call it rcp.view. Now you create another one, which doesnt make UI contributions (only org.eclipse.core.runtime to start with) and call it rcp.presenter. To simplify things, this plugin will also be the model for now.
Next steps:
Add the rcp.presenter to the
dependencies of rcp.view (its
important that the presenter has no
reference to the view)
Export all packages that you are
going to create in the rcp.presenter
so they are visible
In rcp.presenter create an interface
IPerspective that has some methods
like (showLogiDialog(), showAdministratorViews(User user), showStandardViews(User user))
Create a class PerspectivePresenter that takes IPerspective in the constructor and saves it in an attribute
In rcp.view go to your Perspective, implement your interface IPerspective, and in the constructor create a new reference presenter = new PerspectivePresenter(this)
call presenter.load() and implenent
this in the presenter maybe like this
code:
public void load()
{
User user = view.showLoginDialog(); // returns a user with the provided name/pw
user.login(); // login to system/database
if(user.isAdministrator())
view.showAdministratorViews(user);
else
view.showStandardViews(user);
}
As you can see, the view just creates a reference to the presenter, which is responsible for all the business logic, and the presenter tells the view what to display. So in your Perspective you implement those interface functions and in each one you can set up your Perspective in a different way.
For each View it goes in the same way, you will need a presenter for the view which performs operations and tells the view (using the interface) what to display and passing down the final data. The view doesnt care about the logic. This is also very usefull when using JFace-Databindings (then only bound data is passed to the view).
For example, the WorkbenchWindowAdisor will just create everything that is needed in the application. Other views, perspectives, then can enable/disable menus and so on depending on the data they got (like when isAdministrator you might want to enable an special adminMenu).
I know this is quite a heavy approach, but the Eclipse RCP is designed for big (as the name says rich) applications. So you should spend some time in the right architecture. My first RCP app was like you described...I never knew where to store things and how to handle all the references. At my work I learned about MVP (and I am still learning). It takes a while to understand the concept but its worth it.
You might want to look at my second post at this question to get another idea on how you could structure your plugins.