I am currently refactoring my GWT client and try to apply the MVC pattern to all concerned classes. My problem is that I am not sure about two things here:
- Where do I control which view gets displayed? For example if the user logs in and the start page should get loaded. Would the controller load that page or the model?
- How would I best handle asynchronous callbacks and who (model or controller) is supposed to hold the async service?
I have this simple login example that is my actual code as it currently looks like:
LoginModel
// LoginModel appears kind of obsolete ..
public class LoginModel {
private final LoginServiceAsync loginService = LoginService.Util.getInstance();
public void onLoginClick(String userId, String password, AsyncCallback<UserDTO> asyncCallback) {
// Login on the server ..
this.loginService.login(userId, password, asyncCallback);
}
}
LoginView
public class LoginView extends Composite {
private static UILoginUiBinder uiBinder = GWT.create(UILoginUiBinder.class);
@UiField Button btnLogin;
@UiField TextBox txtPassword;
@UiField TextBox txtUserID;
interface UILoginUiBinder extends UiBinder<Widget, LoginView> {
}
public LoginView() {
initWidget(uiBinder.createAndBindUi(this));
}
public void addLoginButtonClickHandler(ClickHandler clickHandler) {
this.btnLogin.addClickHandler(clickHandler);
}
public String getUserId() {
return this.txtUserID.getText();
}
public String getPassword() {
return this.txtPassword.getText();
}
public void displayLoginFailure() {
// TODO display login failure ..
}
}
LoginController
public class LoginController {
private final LoginModel loginModel;
private final LoginView loginView;
public LoginController(LoginModel loginModel, final LoginView loginView) {
this.loginModel = loginModel;
this.loginView = loginView;
this.loginView.addLoginButtonClickHandler(new LoginButtonClickHandler());
}
private class LoginButtonClickHandler implements ClickHandler {
@Override
public void onClick(ClickEvent event) {
loginModel.onLoginClick(loginView.getUserId(), loginView.getPassword(), new AsyncCallback<UserDTO>() {
public void onFailure(Throwable caught) {
onLoginFailure(caught);
}
public void onSuccess(UserDTO userDto) {
onLoginSuccess(userDto);
}
});
}
}
public void onLoginFailure(Throwable caught) {
Throwable cause = caught.getCause();
if (cause instanceof LoginException) {
GWT.log("Cause: " + cause.getMessage());
cause.printStackTrace();
}
this.loginView.displayLoginFailure();
}
public void onLoginSuccess(UserDTO userDto) {
// NOTE: UIStart is what is going to become StartView!
UIStart home = new UIStart();
RootPanel.get("mainUIContainer").clear();
RootPanel.get("mainUIContainer").add(home);
}
}
Is this a good implementation of the MVC pattern? Can I do better?