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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With