GWT: Adding a SubmitHandler to a Form without putting logic in View - gwt

I have a GWTP PresenterWidget and View pair that contains a simple search form.
Currently I am adding the SubmitHandler to the form by calling the getSearchForm() method of my View, which is bad practice as it references the actual class instead of an interface:
public class HeaderPresenter extends PresenterWidget<HeaderPresenter.MyView>
{
public interface MyView extends View
{
void submitForm();
Form getSearchForm();
}
// ...omitted for brevity
#Inject
public HeaderPresenter(EventBus eventBus, DispatchAsync dispatchAsync, MyView view, PlaceManager placeManager)
{
// ...omitted for brevity
}
#Override
protected void onBind()
{
super.onBind();
getView().getSearchForm().addSubmitHandler(new SubmitHandler()
{
#Override
public void onSubmit(SubmitEvent event)
{
// stops the form submission
event.cancel();
// now we can do our stuff
String query = getView().getSearchQuery();
if(query != "") // don't search for a blank string
{
PlaceRequest request = new PlaceRequest.Builder().nameToken(NameTokens.search).with("q", query).build();
placeManager.revealPlace(request);
}
}
});
}
Is there a way to add the SubmitHandler in the HeaderPresenter, or will I have to put that code in the View?
I'd like to keep as much logic in the Presenter as possible.

I found a discussion on this here, and ended up using option 4 as suggested by Thomas Broyer:
https://groups.google.com/forum/#!topic/google-web-toolkit/Fbo-SEDjRa4

Related

GWTP ViewWithUiHandlers: uiHandlers are not set. Did you call getUiHandlers() from your view's constructor? in PresenterWidget

I have problem that I do not understand. I think I've done what I supposed to do, but it dosnt work.
I cannot executed presenter methods from view using ui handlers. Error says that I did not set ui handlers but I did:
#Inject
FileUploaderPresenter(EventBus eventBus, MyView view, PlaceManager placeManager) {
super(eventBus, view);
getView().setUiHandlers(this);
this.placeManager = placeManager;
}
and
public FileUploaderView() {
super();
this.getUiHandlers();
this.initWidget(uploader);
}
But I am getting an error:
com.gwtplatform.mvp.client.ViewWithUiHandlers
SEVERE: uiHandlers are not set. Did you call getUiHandlers() from your view's constructor?
For sure I will post all my classes related:
public class FileUploaderModule extends AbstractPresenterModule {
#Override
protected void configure() {
bindSingletonPresenterWidget(FileUploaderPresenter.class, FileUploaderPresenter.MyView.class, FileUploaderView.class);
}
}
public class FileUploaderPresenter extends PresenterWidget<FileUploaderPresenter.MyView> implements FileUploaderUiHandlers {
interface MyView extends View, HasUiHandlers<FileUploaderUiHandlers> {
}
PlaceManager placeManager;
#Inject
FileUploaderPresenter(EventBus eventBus, MyView view, PlaceManager placeManager) {
super(eventBus, view);
getView().setUiHandlers(this);
this.placeManager = placeManager;
}
#Override
protected void onBind() {
super.onBind();
}
#Override
public void onOk() {
Routing.Redirect.toLoginPage(placeManager);
}
#Override
public void onUnauthorized() {
Routing.Redirect.toLoginPage(placeManager);
}
}
interface FileUploaderUiHandlers extends UiHandlers {
void onUnauthorized();
void onOk();
}
public class FileUploaderView extends ViewWithUiHandlers<FileUploaderUiHandlers> implements FileUploaderPresenter.MyView {
MaterialFileUploader uploader = new MaterialFileUploader();
public FileUploaderView() {
super();
this.getUiHandlers();
this.initWidget(uploader);
MaterialUploadLabel label = new MaterialUploadLabel();
label.setTitle("Put Your's files here and here");
label.setDescription("Some description here");
uploader.add(label);
uploader.setMaxFileSize(10000000);
uploader.setUrl(ServiceRouting.FULL_SERVICE + ServiceRouting.FileService.upload);
addHandlers();
}
private void addHandlers() {
uploader.addUnauthorizedHandler(new UnauthorizedHandler<UploadFile>() {
#Override
public void onUnauthorized(UnauthorizedEvent<UploadFile> event) {
GWT.log("UnauthorizedEvent (" + event.getTarget().getName() + " | " + event.getResponse().getCode() + " | " + event.getResponse().getMessage() + "|" + event.getResponse().getBody()
+ ")");
MaterialToast.fireToast("Redirect to login page");
getUiHandlers().onUnauthorized();
}
});
}
I instantialize this widget with: FileUploaderView()
Is this error happens, cause I don't use uiBinder?
This is my first PresenterWidget. Maybe it should be done differently from standard Presenter. Any help appreciated.
Alright, I've figure it out on my own.
The problem is that This Presenter/View pair is a widget. So it should be instantialize with slot mechanism of gwtp. And to do this we use bind method with Presenter class parameter (not view like I was doing).
#Inject UploaderPresenter fileUploaderPresenter;
#Override
protected void onBind() {
super.onBind();
setInSlot(SLOT_FILE_UPLOAD, fileUploaderPresenter);
}
Here is documentation:
http://dev.arcbees.com/gwtp/tutorials/tutorial-part2.html
sections:
Binding the PresenterWidget
Set in slot
Bind Slot
http://dev.arcbees.com/gwtp/core/presenters/
Ok, just let's trace the steps from your code:
This is the constructor of your presenter. MyView view injected here WAS ALREADY CREATED here to be passed to your constructor.
#Inject
FileUploaderPresenter(EventBus eventBus, MyView view, PlaceManager placeManager) {
super(eventBus, view);
getView().setUiHandlers(this)
which means
public FileUploaderView() {
super();
this.getUiHandlers();
this.initWidget(uploader);
}
is called BEFORE presenter contructor. So you call this.getUiHandlers() before you set them in Presenter's constructor.
Move the call to some kind of #UiHandler

GWT: Showing a String list in DataGrid

i got a Presenter that is supposed to present a popup window what contains a DataGrip to show log file entries from a String list. I try to set the appropriate settings, but the number of log file lines that are displayed do not match the String list. I tried to enhance the data assignment, resulting in the Presenter not being shown any more.
Could you please give me a hint what i am doing wrong?
The parts of my presenter related to the DataGrid are:
// Create a list data provider.
final ListDataProvider<String> dataProvider = new ListDataProvider<String>();
public interface MyView extends PopupView, HasUiHandlers<DeviceLogfileUiHandlers> {
DataGrid<String> getDataGrid();
}
#Inject
DeviceLogfilePresenterWidget(final EventBus eventBus, final MyView view) {
super(eventBus, view);
getView().setUiHandlers(this);
}
protected void onBind() {
super.onBind();
// Add the cellList to the dataProvider.
dataProvider.addDataDisplay(getView().getDataGrid());
TextColumn<String> stringColumn = new TextColumn<String>() {
#Override
public String getValue(String s) {
return s;
}
};
getView().getDataGrid().addColumn(stringColumn);
}
#Override
protected void onReveal() {
super.onReveal();
}
public void setDeviceLog(List<String> logEntries) {
getView().getDataGrid().setRowData(0, logEntries);
//These entries make the presenter not show up any more:
dataProvider.addDataDisplay(getView().getDataGrid());
dataProvider.setList(logEntries);
getView().getDataGrid().setRowCount(logEntries.size(), true);
getView().getDataGrid().setVisibleRange(0, logEntries.size());
getView().getDataGrid().setPageSize(logEntries.size());
getView().getDataGrid().redraw();
}

GWT's Editor Framework and GWTP

building on this answer, i try to integrate the GWT editors into a popup presenter widget. What is the right way to do that?
My view looks like this:
public class DeviceEditorDialogView extends
PopupViewWithUiHandlers<DeviceEditorDialogUiHandlers> implements
DeviceEditorDialogPresenterWidget.MyView {
interface Binder extends UiBinder<PopupPanel, DeviceEditorDialogView> {
}
public interface Driver extends SimpleBeanEditorDriver<DeviceDto, DeviceEditorDialogView> {
}
#Inject
DeviceEditorDialogView(Binder uiBinder, EventBus eventBus) {
super(eventBus);
initWidget(uiBinder.createAndBindUi(this));
}
#Override
public SimpleBeanEditorDriver<DeviceDto, ?> createEditorDriver() {
Driver driver = GWT.create(Driver.class);
driver.initialize(this);
return driver;
}
}
and my presenter looks like this:
public class DeviceEditorDialogPresenterWidget extends PresenterWidget<DeviceEditorDialogPresenterWidget.MyView> implements
DeviceEditorDialogUiHandlers {
#Inject
DeviceEditorDialogPresenterWidget(EventBus eventBus,
MyView view) {
super(eventBus, view);
getView().setUiHandlers(this);
}
/**
* {#link LocalDialogPresenterWidget}'s PopupView.
*/
public interface MyView extends PopupView, DevicesEditView<DeviceDto>, HasUiHandlers<DeviceEditorDialogUiHandlers> {
}
private DeviceDto currentDeviceDTO = null;
private SimpleBeanEditorDriver<DeviceDto, ?> driver;
public DeviceDto getCurrentDeviceDTO() {
return currentDeviceDTO;
}
public void setCurrentDeviceDTO(DeviceDto currentDeviceDTO) {
this.currentDeviceDTO = currentDeviceDTO;
}
#Override
protected void onBind() {
super.onBind();
driver = getView().createEditorDriver();
}
//UiHandler Method: Person person = driver.flush();
}
Is this the right approach? What is missing? Currently nothing happens when i try to use it like this:
#Override
public void showDeviceDialog() {
deviceEditorDialog.setCurrentDeviceDTO(new DeviceDto());
addToPopupSlot(deviceEditorDialog);
}
showDeviceDialog is in the parent presenter and called when clicking a button in that parent Presenter, that instantiates the dialog with private final DeviceEditorDialogPresenterWidget deviceEditorDialog;
Thanks!
Here are a few key points that are missing from your code above:
Your DeviceEditorDialogView should implement Editor<DeviceDto>. This is required in order for the fields of DeviceEditorDialogView to be populated with data from you POJO.
Your DeviceEditorDialogView should have child editors that are mapped to fields in your POJO. For example, given the field deviceDto.modelName (type String), you could have a GWT Label named modelName in your DeviceEditorDialogView. This Label implements Editor<String> and will be populated with the modelName from your DeviceDto when you call driver.edit(deviceDto)
You should call driver.initialize(this) only once, in DeviceEditorDialogView's constructor
You should override onReveal() like this:
#Override
public void onReveal() {
super.onReveal();
driver.edit(currentDeviceDTO); // this will populate your view with the data from your POJO
}
This method will be called when the popup is displayed, just after your DeviceEditorDialogPresenterWidget has been addToPopupSlot

In GWTP how can TabLayoutPanel events be handled?

I've followed Dani's GWTP Course but using TabLayoutPanel with presenters isn't covered.
I have a TabLayoutPanel with 3 tabs (each with a VerticalPanel on it). I've used #ProxyCodeSplit so that the code for each tab is loaded independently.
If in Eclipse, in GWT's Designer I add a handler for OnBeforeSelection then code is auto-added into my View. The View can then load up the appropriate presenter.
That doesn't feel like the right place for the code - but is it?
How are you handing different tabs within TabLayoutPanel and code splitting?
I think I've got this figured out.
In your presenter with the TabLayoutPanel (let's call it MainPresenter):
#ContentSlot public static final Type<RevealContentHandler<?>> SLOT_first = new Type<RevealContentHandler<?>>();
#ContentSlot public static final Type<RevealContentHandler<?>> SLOT_second = new Type<RevealContentHandler<?>>();
public interface MyView extends View {
public void setMainPresenter(MainPresenter presenter);
public TabLayoutPanel getTeamsPanel();
}
#Inject PlaceManager placeMananger;
#Inject FirstPresenter firstPresenter;
#Inject SecondPresenter secondPresenter;
#ProxyCodeSplit
public interface MyProxy extends Proxy<MainPresenter> {
}
#Inject
public MainPresenter(final EventBus eventBus, final MyView view,
final MyProxy proxy) {
super(eventBus, view, proxy);
view.setMainPresenter(this);
}
#Override
protected void revealInParent() {
RevealRootContentEvent.fire(this, this);
}
public void setTabContents(Integer tab) {
if (tab == 0) {
placeMananger.revealPlace(new PlaceRequest("first"));
} else if (tab == 1) {
placeMananger.revealPlace(new PlaceRequest("second"));
}
Then in your MainView implement the method setMainPresenter() to store a reference locally. Implement the usual setInSlot() and then add this tab handler:
#UiHandler("mainTabs")
void onMainTabsBeforeSelection(BeforeSelectionEvent<Integer> event) {
mainPresenter.setTabContents(event.getItem());
}
The handler will call MainPresenter each time the user changes tabs. setTabContents() will then call revealInParent() for the appropriate "tab" Presenter.

What is the proper way to use gwt-bootstrap modal with gwt-platform?

I am constructiong an webapp with Google Web Toolkit using GWT-Platform and GWT-Bootstrap frameworks. Mostly it has been almost flawless until I tried to implement a popup. These frameworks' undestanding of popups seems to be quite different.
GWT-Platform expects a popup widget itself to be an instance of com.google.gwt.user.client.ui.PopupPanel when using the GWTP's RevealRootPopupContentEvent.fire(source, content) or a presenter's addToPopupSlot(child) method.
GWT-Bootstrap's Modal is used like any other widget that is added to the underlying panel but my goal is it to have a separate presenter and view and to possibly fetch it asynchrously with AsyncProvider.
I have tried to make it as a PresenterWidget and using addToSlot(slot, content) to reveal it but it doesn't look quite right. Not all of the styles are applied this way and the close icon (×), doesn't work for example.
I think I am not the first one trying to do something like that so maybe someone has figured out a proper way to make it work.
Thanks!
You have to create a view:
public class MyPopupView extends PopupViewImpl implements MyView {
protected Widget widget;
public interface MyPopupViewUiBinder extends
UiBinder<Widget, MyPopupView> {
}
#UiField(provided = true)
Modal dialogBox;
private MyPresenter presenter;
#Inject
public MyPopupView(final MyPopupViewUiBinder uiBinder,
final EventBus eventBus) {
super(eventBus);
setUpDialog(); // Provides UiField => Before initWidgets
initWidget(uiBinder.createAndBindUi(this));
}
// DialogBox must be overridden to let the presenter handle changes onUnload
private void setUpDialog() {
dialogBox = new Modal() {
#Override
protected void onUnload() {
MyPopupView.this.hide();
}
};
dialogBox.setTitle("Some title");
}
#Override
public void setPresenter(final MyPresenter presenter) {
this.presenter = presenter;
}
#Override
public final void hide() {
dialogBox.hide();
presenter.hide();
}
#Override
public void setAutoHideOnNavigationEventEnabled(final boolean autoHide) {
// TODO Auto-generated method stub
}
#Override
public void setCloseHandler(
final PopupViewCloseHandler popupViewCloseHandler) {
// TODO Auto-generated method stub
}
#Override
public void setPosition(final int left, final int top) {
// TODO Auto-generated method stub
}
#Override
public void show() {
dialogBox.show();
}
#Override
public void center() {
dialogBox.show();
}
#Override
public Widget asWidget() {
return widget;
}
protected final void initWidget(final Widget widget) {
this.widget = widget;
}
}
And a UIBinder file:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:b='urn:import:com.github.gwtbootstrap.client.ui'>
<b:Modal title="Some Title" ui:field="dialogBox">
<!-- Your content -->
</b:Modal>
</ui:UiBinder>
Your gwtp popup presenter has a view that extends PopUpViewImpl which implements PopupView, and uses a lot of the methods of that interface for displaying the popup (asPopupPanel(), show(), center(), etc).
I'm just starting to get to know gwt-bootstrap (looks great +caalos0), but it seems that Modal doesn't implement PopupView, and therefore cannot be passed to addToPopupSlot in a way it would be displayed automatically by gwtp.
as for the addToSlot() issue, are you using RootLayoutPanel or RootPanel?
it could be the reason for addToSlot not working properly, since the gwt-bootstrap Modal widget is attached to the RootPanel on initialization, this can cause weird layout behavior along with an application using RootLayoutPanel as base.
I would try to extend the Modal component, let it implement PopUpView, add it as a field on the PopUpViewImpl attached to your popup presenter, and override the PopUpViewImpl asPopupPanel() function to return the new extended Modal.
Based on the answer by #dominik I did some improvements, see my Gist. It contains some abstract base classes that can be used for any Modal/PopupView implementation. It's a bit more complex but also cleaner because we don't pass the whole Presenter to the View. The interface for the View to interact with the Presenter when the modal is closed is HasModalUnbind.
You would use these classes as follows. Example presenter:
public class ErrorModalPresenter extends ModalPopupPresenter<ErrorModalPresenter.MyView> {
public interface MyView extends ModalPopupView {
DivElement getErrorMessage();
}
private final ErrorEvent error;
#Inject
public ErrorModalPresenter(final EventBus eventBus,
final MyView view,
#Assisted final ErrorEvent error) {
super(eventBus, view);
this.error = error;
}
#Override
public void unbindModal() {
ErrorDismissEvent.fire(this, this);
}
#Override
protected void onBind() {
super.onBind();
//noinspection ThrowableResultOfMethodCallIgnored
getView().getErrorMessage().setInnerText(error.getCause().getMessage());
}
}
Example view:
public class ErrorModalView extends ModalPopupViewImpl implements ErrorModalPresenter.MyView {
#UiField(provided = true)
Modal errorModal;
#UiField
DivElement errorMessage;
interface Binder extends UiBinder<Widget, ErrorModalView> {}
#Inject
public ErrorModalView(final EventBus eventBus,
final Binder uiBinder) {
super(eventBus);
errorModal = initModal();
initWidget(uiBinder.createAndBindUi(this));
}
#Override
public DivElement getErrorMessage() {
return errorMessage;
}
}
And the UiBinder XML just for the record:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:b='urn:import:com.github.gwtbootstrap.client.ui'>
<b:Modal ui:field='errorModal' title='Error'>
<g:HTML>
<div ui:field='errorMessage'/>
</g:HTML>
<b:ModalFooter>
<b:Button text='Close' dismiss='MODAL'/>
</b:ModalFooter>
</b:Modal>
</ui:UiBinder>
In unbindModal() of ErrorModalPresenter I fire an event which is caught by the parent presenter of ErrorModalPresenter. There the modal presenter is removed from a container and then unbind() is called on the presenter. Of course any other solution is possible in unbindModal().
The base classes assume that modals are one-shot modals that will be removed once they're hidden. This behaviour can be changed in initModal() of ModalPopupViewImpl.
I believe you will have to made some Glue Code to made it works.
I never used GWT-Platform popups, so I dont know exactly how, but I believe you will have to made a new Class extending PopupPresenter, and made what's needed to made it work.
Also, I was thinking about GWT-Platform days ago... and I'm pretty sure that when first release of GWT-Platform is out, I'll create a new project to made these necessary glue codes.
If you need any help with this, please contact me.
Thanks, sorry about the poor gwt-platform support.