Search code examples
gwtwidgetcompositeuibinder

GWT - Cant use a composite widgets clickhandlers


I am trying to create a composite widget that encapsulates my menu bar. I want it to have the click handlers defined so that I can simply add it to any .ui.xml that I create.

This is my menu bar ui.xml

<!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:v="urn:import:com.epiuse.cloud.portal.ui.client.view"
  xmlns:widget="urn:import:com....client.widgets">


<g:AbsolutePanel styleName="navBar">
    <g:HTMLPanel>
    <ul>
        <li><g:HTML ui:field="aboutLink"><a>About</a></g:HTML></li>
        <li>|</li>
        <li><g:HTML ui:field="contactLink"><a>Contact</a></g:HTML></li>
        <li>|</li>
        <li><g:HTML ui:field="loginLink"><a>Login</a></g:HTML></li>
    </ul>
    </g:HTMLPanel>
</g:AbsolutePanel>  
</ui:UiBinder> 

This is the associated view:

public class GeneralMenuBarImpl  extends Composite implements GeneralMenuBar {

@UiTemplate("GeneralMenuBar.ui.xml")
interface GeneralMenuBarImplUiBinder extends UiBinder<Widget, GeneralMenuBarImpl> {}
private static GeneralMenuBarImplUiBinder uiBinder =
       GWT.create(GeneralMenuBarImplUiBinder.class);

 private Presenter presenter;

 @UiField HTML loginLink;
 @UiField HTML contactLink;
 @UiField HTML aboutLink;


 public GeneralMenuBarImpl(){

     initWidget(uiBinder.createAndBindUi(this));

 }

public void setPresenter(Presenter presenter){
     this.presenter = presenter;
}



 @UiHandler("loginLink")
void onLoginLinkClicked(ClickEvent event) {
    presenter.onLoginLinkClicked();
}
@UiHandler("contactLink")
void onContactLinkClicked(ClickEvent event) {
    presenter.onContactLinkClicked();
}
@UiHandler("aboutLink")
void onAboutLinkClicked(ClickEvent event) {
    presenter.onAboutLinkClicked();
}

public Widget asWidget(){
     return this;
 }

}

I then include it on my home page by adding the correct namespace to the ui.xml file and then add the following line.

<widget:GeneralMenuBarImpl></widget:GeneralMenuBarImpl>

This works to display the menu bar, but my click handlers are not working. I suspect it is because the menu bar has not received a presenter in which to tell an event has occurred.

So my question is this: How can I either pass a presenter to the included widget or access the uiFields of the widget from the page I am including it on?

I hope some one is able to help. Been stuck on this problem for ages!

Thanks in advance guys!


Solution

  • Two ways to solve this:

    • You could expose your Links in your Composite so you can access it from the containing page. The containing page could attach EventHandlers to your links and handle the events there.

    Composite:

    public HasClickhandlers getAboutLink() {
        return aboutLink
    }
    

    Page:

    menuBar.getAboutLink.addClickHandlers(new ClickEvent() {
    });
    
    • You have to set the Presenter in your Composite from the parent page/presenter (menuBar.setPresenter(this);) where you include your composite. Then you can handle the clicks by the interface contract between presenter and Composite.

    The first approach breaks a little bit with the MVP pattern. The second approach is more MVP like in this regard. However you have to think about following questions:

    • Is your composite just a widget or does it have enough business logic to make a PresenterWidget out of it (define Presenter/View pair).
    • If the widget is only a simple widget then defining a presenter might be an overkill (go with approach 1).
    • In case you want to handle the clicks application wide you can also fire an event on the application wide EventBus