Skip to main content

Home/ Groups/ GWT - MVP
Esfand S

Ray Ryan, best practices and embracing asynchronicity - Google Web Toolkit | Google Groups - 0 views

  • there is a clear distinction between *what the browser needs* (DTO) and *what the business needs* (domain objects). When you send JDO objects across the wire, you are sending your domain model. Its not what the browser wants, and that is a problem. Soon, you will have a presentational information in your domain model, and you will have restricted information being sent to the browser, and it will be a big mess. So, take a step back, and separate Domain objects from Presentation objects (or DTOs). Make your RPCs revolve around a particular view, and send all necessary information for that view in one RPC call. Note that now your Person would include company name and company id, but not the entire company object. Now, when the user clicks the company in the view, you make a RPC call to get company information (because you have company id). That's it. Works nicely, without having to make multiple calls.
Esfand S

Large scale application development and MVP - Part II - 0 views

  • segment the code that declares the UI from the code that drives the UI.
  • we want the our ContactsPresenter to implement a Presenter interface that allows our ContactsView to callback into the presenter when it receives a click, select or other event. The Presenter interface defines the following:   public interface Presenter<T> {    void onAddButtonClicked();    void onDeleteButtonClicked();    void onItemClicked(T clickedItem);    void onItemSelected(T selectedItem);  }
  • The first part of wiring everything up is to have our ContactsPresenter implement the Presenter interface, and then register itself with the underlying view. To register itself, we'll need our ContactsView to expose a setPresenter() method:   private Presenter<T> presenter;  public void setPresenter(Presenter<T> presenter) {    this.presenter = presenter;  }
  • ...8 more annotations...
  • Note that our ContactsView is now ContactsViewImpl<T> and implements ContactsView<T>. This is so that we can pass in a mocked ContactsView instance when testing our ContactsPresenter. Now in our AppController, when we create the ContactsView, we can initialize it with the necessary ColumnDefinition(s).
  • With the ColumnDefinition(s) in place, we will start to see the fruits of our labor. Mainly in the way we pass model data to the view. As mentioned above we were previously dumbing down the model into a list of Strings. With our ColumnDefinition(s) we can pass the model untouched.   public class ContactsPresenter implements Presenter,    ...    private void fetchContactDetails() {      rpcService.getContactDetails(new AsyncCallback<ArrayList<ContactDetails>>() {        public void onSuccess(ArrayList<ContactDetails> result) {            contactDetails = result;            sortContactDetails();            view.setRowData(contactDetails);        }        ...      });    }    ...  } And our ContactsViewImpl has the following setRowData() implementation:   public class ContactsViewImpl<T> extends Composite implements ContactsView<T> {    ...    public void setRowData(List<T> rowData) {      contactsTable.removeAllRows();      this.rowData = rowData;      for (int i = 0; i < rowData.size(); ++i) {        T t = rowData.get(i);        for (int j = 0; j < columnDefinitions.size(); ++j) {          ColumnDefinition<T> columnDefinition = columnDefinitions.get(j);          contactsTable.setWidget(i, j, columnDefinition.render(t));        }      }    }    ...  } A definite improvement; the presenter can pass the model untouched and the view has no rendering code that we would otherwise need to test.
  • Code Splitting is the act of wrapping segmented pieces of your application into "split" points by declaring them within a runAsync() call. As long as the split portion of your code is purely segmented, and not referenced by other parts of the app, it will be downloaded and executed at the point that it needs to run.
  • We've figured out how to create the foundation for complex UIs while sticking to our requirement that the view remain as dumb (and minimally testable) as possible, but that's no reason to stop. While functionality is decoupled, there is still room for optimization. Having the ColumnDefinition create a new widget for each cell is too heavy, and can quickly lead to performance degradation as your application grows. The two leading factors of this degradation are: Inefficiencies related to inserting new elements via DOM manipulation Overhead associated with sinking events per Widget To overcome this we will update our application to do the following (in respective order): Replace our FlexTable implementation with an HTML widget that we'll populate by calling setHTML(), effectively batching all DOM manipulation into a single call. Reduce the event overhead by sinking events on the HTML widget, rather than the individual cells. The changes are encompassed within our ContactsView.ui.xml file, as well as our setRowData() and onTableClicked() methods. First we'll need to update our ContactsView.ui.xml file to use a HTML widget rather than a FlexTable widget.
  • The above code is similar to our original setRowData() method, we iterate through the rowData and for each item ask our column definitions to render accordingly. The main differences being that a) we're expecting each column definition to render itself into the StringBuilder rather than passing back a full-on widget, and b) we're calling setHTML on a HTML widget rather than calling setWidget on a FlexTable. This will decrease your load time, especially as your tables start to grow.
  • To reiterate, we're reducing the overhead of sinking events on per-cell widgets, and instead sinking on a single container, our HTML widget. The ClickEvents are still wired up via our UiHandler annotations, but with this approach, we're going to get the Element that was clicked on and walk the DOM until we find a parent TableCellElement. From there we can determine the row, and thus the corresponding rowData.
  • Our current solution is to have our presenters pass a dumbed down version of the model to our views. In the case of our ContactsView, the presenter takes a list of DTOs (Data Transfer Objects) and constructs a list of Strings that it then passes to the view. public ContactsPresenter implements Presenter {  ...  public void onSuccess(ArrayList<ContactDetails> result) {    contactDetails = result;    sortContactDetails();    List<String> data = new ArrayList<String>();    for (int i = 0; i < result.size(); ++i) {      data.add(contactDetails.get(i).getDisplayName());    }    display.setData(data);  }  ...} The "data" object that is passed to the view is a very (and I mean very) simplistic ViewModel — basically a representation of a more complex data model using primitives. This is fine for a simplistic view, but as soon as you start to do something more complex, you quickly realize that something has to give. Either the presenter needs to know more about the view (making it hard to swap out views for other platforms), or the view needs to know more about the data model (ultimately making your view smarter, thus requiring more GwtTestCases). The solution is to use generics along with a third party that abstracts any knowledge of a cell's data type, as well as how that data type is rendered.
  •         // TODO: Really total hack! There's gotta be a better way...        Element child = cell.getFirstChildElement();        if (child != null) {          Event.sinkEvents(child, Event.ONFOCUS | Event.ONBLUR);        }
Marco Antonio Almeida

Sanjiv Jivan's Blog - 0 views

  • Once a DataSource has been defined to describe your entity / domain class, data can be read into a DataSource from a wide variety of sources. For example local array data, XML or JSON, data from the server, or you can even point to sample test data. The DataSource has a build-in mechanism to communicate with the source of the data, whether local or the backend server, for the four key operations : FETCH, ADD, UPDATE and REMOVE.
Esfand S

MVP vs MVC - 0 views

  •  
    In MVC, the model is heavy with business rules and data access, the view contains the presentation logic, and the controller is typically a framework component with an XML configuration to drive it. In MVP, the model is lightweight POJO value objects, the view is mockable, and the presentation is specific to the model and the view. It is the presentation that has all the dependencies and glue code for the model\nand the view. You get more code coverage in your unit testing with MVP so MVP and TDD go together.
Esfand S

Client session - Google Web Toolkit | Google Groups - 0 views

  • The way I would do is to define a application event (eg. LocationEvent<LocationHandler>) & handler encapsulating whatever data (ex. co ordinates) that you need to send and fire the event. First presenter fires the event when the mouse is clicked. Second Presenter handles the event and takes appropriate action.
Esfand S

Ray Ryan, best practices and embracing asynchronicity - Google Web Toolkit | Google Groups - 0 views

  • Doing this well depends on some form of centralized data retrieve dispatch/caching.  You make calls to this centralized service to get the objects by id that you are interested in.   It either finds them in cache and can return them immediately, or adds them to a queue of objects to retrieve.  After all requests have been made (ie on DeferredCommand), a single request is sent to retrieve all objects of all types needed.
  • You could use an event bus to indicate all the objects where data is now available. This could even be a single event instead of one for each object, and the event handlers can ask if their objects of interest are now available, avoiding multiple updates.
Esfand S

GWT 2.1 hellomvp using GIN - Google Web Toolkit | Google Groups - 0 views

  • although we can't map a 1-Many relationship between a Place and an Activity, you can in fact map multiple places to the same activity and differentiate between the place with multiple init() methods in the activity.
Esfand S

GWT MVP Development with Activities and Places - Google Web Toolkit - Google Code - 0 views

  • How to navigate To navigate to a new Place in your application, call the goTo() method on your PlaceController. This is illustrated above in the goTo() method of HelloActivity. PlaceController warns the current Activity that it may be stopping (via a PlaceChangeRequest event) and once allowed, fires a PlaceChangeEvent with the new Place. The PlaceHistoryHandler listens for PlaceChangeEvents and updates the URL history token accordingly. The ActivityManager also listens for PlaceChangeEvents and uses your app's ActivityMapper to start the Activity associated with the new Place. Rather than using PlaceController.goTo(), you can also create a Hyperlink containing the history token for the new Place obtained by calling your PlaceHistoryMapper.getToken(). When the user navigates to a new URL (via hyperlink, back button, or bookmark), PlaceHistoryHandler catches the ValueChangeEvent from the History object and calls your app's PlaceHistoryMapper to turn the history token into its corresponding Place. It then calls PlaceController.goTo() with the new Place. What about apps with multiple panels in the same window whose state should all be saved together in a single URL? GWT 2.1 does not attempt to provide a generic implementation of a composite Place; however, your app could create a CompositePlace, CompositeActivity, and CompositePlace.Tokenizer classes that delegate to the constituent members. In this case, only the composite objects would need to be registered with your app's ActivityMapper and PlaceHistoryMapper.
Esfand S

design pattern for common functionality between Activities - Google Web Toolkit | Googl... - 0 views

  • How I understand things, a display region is a dynamic part of a webpage; Depending on the place you're at, a display region is populated with a specific activity. A activity manager is the manager of a display region and decides the right activity to show up for a given display region when a certain page is showing. So, in terms of your question : a display region can be a dynamic menu, a sidebar, a logout/login link.... not the entire group. An example page with menu displayregion, maincontent displayregion, sidebar displayregion example page #ContactDetailsPage:FooBar +> sidebar display region will be instructed by the sidebar- activitymanager to start the activity GrandChildrenActivity (display grandchildren in side bar) +> maincontact display region will be instructed by the maincontentarea-activitymanager to start the activity ContactDetailsActivity (display contact details in main content area) +> menu display region will be instructed by the menu-activitymanager to start the activity MenuActivity (show the menu) example page #Login +> sidebar display region will be instructed by the sidebar- activitymanager to display nothing (NULL) +> maincontact display region will be instructed by the maincontentarea-activitymanager to start the activity LoginActivity (display login page) +> menu display region will be instructed by the menu-activitymanager to start the activity WelcomeActivity (show a welcome msg) etc etc.
  • places and activities are orthogonal to each other a webpage consists of many display regions every display region is managed by a activity manager when a place change occurs, the activity managers are notified and they decide the activity to live inside the display region
  • Actually HelloMVP is a really confusing example, because - the activities are called HelloActivity and GoodbyeActivity - the places are called HelloPlace and GoodbyePlace but the activities and places are orthogonal to each other. That doesn't help to get a clearer understanding.
Esfand S

Sample App using DI/Gin, MVP, UiBinder, etc - Google Web Toolkit | Google Groups - 0 views

  • * I notice that you're injecting instances of your activities into your activity mapper. Activities are meant to be fairly lightweight objects, as opposed to the views that represent them, so they don't need to be singletons (which they effectively are since you have a single app with a single injected activity mapper). It's probably not necessarily a problem unless your activities have state associated with them (such as the entity that the user is currently working with), which you have to be careful to clear out between uses with different data. The same can be said about places.
  • My understanding is that you only want a single area of the shell to be managed by one ActivityManager. So if you have an entire shell/layout with more than one area that changes, let's say a main content area as well as a context menu (If I have MainAppPlace and SettingsAppPlace and OtherAppPlace both of which extend MainAppPlace, and you want to show a different context menu for Place of type SettingsAppPlace and places of type OtherAppPlace) I would just have main Shell that has a SimplePanel for content and Simplepanel for context_menu I just use an ActivityManager to control one spot of the main layout. is this not right? do you want your activitymanager controlling more than one area??
« First ‹ Previous 61 - 80 Next › Last »
Showing 20 items per page