I'm trying to access some objects inside a ui:binder component, but not sure of how to access the eventBus, requestFactory, etc without writing nasty code that will keep me awake at night (also take note that I'm completely new to JAVA, background is in Perl/Python/PHP).
My ui.xml file:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:ig='urn:import:com.ig.client.scaffold.ui.widget'>
<ui:style>
...
</ui:style>
<g:HorizontalPanel>
...
</g:HorizontalPanel>
</ui:UiBinder>
Injecting the eventBus this way fails with
com.ig.client.scaffold.ui.widget.R has no default (zero args) constructor.
public class R extends Composite {
interface MyUiBinder extends UiBinder<Widget, R> {}
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
private final EventBus eventBus;
#UiField SimplePanel fieldA, ...;
#Inject
public R(EventBus eventBus){
this.eventBus = eventBus;
initWidget(uiBinder.createAndBindUi(this));
}
}
So, as per the error message, I create a UIFactory and then I get an error
... '{style.entityComponent}'> missing required attribute(s): eventBus Element ... (seems like it is trying to find the eventBus in the ui:binder stylesheet.
public class R extends Composite {
interface MyUiBinder extends UiBinder<Widget, R> {}
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
private final EventBus eventBus;
#UiField SimplePanel fieldA, ...;
public #UiConstructor R(EventBus eventBus){
this.eventBus = eventBus;
initWidget(uiBinder.createAndBindUi(this));
}
#Inject
#UiFactory R makeR(){
return new R(eventBus);
}
}
From reading and reading and more reading for the past couple of days, I haven't seen anyone accessing the eventBus, requestFactory and historyController directly in the view binding to the ui:binder widget which led to the conclusion that it's probably not a best practice
anyway.
Let's say I have an oject, let's call it Proxy, proxy contains handleButtonClick which then calls eventBus.doSomething(). How do I link this Proxy object to the ui:binder widget without having to instantiate it or without having to pass it around to every widget?
Is it possible to do GIN injection on an interface and then implement that interface via class R which will then somehow contain the objects I'm looking for?
Any solution that work is welcome, just looking for a sample (that a Java n00b can understand) that will basically allow me to connect my front-end with the rest of the services created by ROO.
Thanks
J
Check out the Model, View, Presenter pattern - it solves
this problem. Generally all non-display logic should be kept out
of your views so that 1) the non-display logic can be unit tested without
running inside a (slow to instantiate) browser and 2) different
displays can be plugged into the same application without duplicating
the non-display logic.
Here's an MVP example exhibiting the
behavior you're looking for (note that the style is slightly
different than the Activities & Places implementation).
MyPresenter.java:
public class MyPresenter {
public interface Display extends IsWidget {
void setButtonClickHandler(ClickHandler buttonClickHandler);
}
private final Display display;
private final EventBus eventBus;
#Inject
public MyPresenter(EventBus eventBus,
Display display)
{
this.display = display;
this.eventBus = eventBus;
bind();
}
private void bind() {
display.setButtonClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
eventBus.fireEvent(new MyButtonClickedEvent());
}
});
}
public void go(HasWidgets container) {
container.add(display.asWidget());
}
}
MyView.ui.xml:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:ig='urn:import:com.ig.client.scaffold.ui.widget'>
<g:Button ui:field="myButton"/>
</ui:UiBinder>
MyView.java
public class MyView extends Composite implements MyPresenter.Display {
interface MyViewUiBinder extends UiBinder<Widget, MyView> {}
private static MyViewUiBinder uiBinder = GWT.Create(MyViewUiBinder.class);
private ClickHandler buttonClickHandler = null;
public MyView() {
initWidget(uiBinder.createAndBindUi(this));
}
#UiHandler("myButton")
void onButtonClick(ClickEvent event) {
if (buttonClickHandler != null) {
buttonClickHandler.onClick(event);
}
}
#Override
public void setButtonClickHandler(ClickHandler buttonClickHandler) {
this.buttonClickHandler = buttonClickHandler;
}
}
And in your GIN module: bind(MyPresenter.Display.class).to(MyView.class);
Related
i have this issue:
I have a PresenterWidget which contains sub-editors.
There are "container" elements which should be editable by this widget. These containers can be assigned to groups. To do so, i would like to fetch a list of all available groups from the server. So the widget is set up like this (i use GWTP):
public class ContainerEditorDialogPresenterWidget extends PresenterWidget<ContainerEditorDialogPresenterWidget.MyView> implements
ContainerEditorDialogUiHandlers {
private final PlaceManager placeManager;
private List<GroupDTO> groupList = new ArrayList<GroupDTO>();
private final DispatchAsync dispatcher;
#Inject
ContainerEditorDialogPresenterWidget(EventBus eventBus,
MyView view, PlaceManager placeManager, DispatchAsync dispatcher) {
super(eventBus, view);
getView().setUiHandlers(this);
this.dispatcher = dispatcher;
fetchGroups();
}
...
public void fetchGroups(){
FetchGroupsAction action = new FetchGroupsAction();
dispatcher.execute(action, new AsyncCallbackImpl<FetchGroupsResult>() {
#Override
public void onSuccess(FetchGroupsResult result) {
groupList = result.getGroupDtos();
eventBus.fireEvent(new GroupListUpdatedEvent(groupList));
}
});
}
So i call fetchGroups in the constructor to get it as early as possible. Since it is an AynchCallback, i get the result back "at some time". I then try to pass the values to the sub-editor with a GroupListUpdatedEvent. In there i have a Editor declared like this:
public class GroupListEditor extends Composite implements
IsEditor<ListEditor<String, GroupItemEditor>> {
private static StringListEditorUiBinder uiBinder = GWT
.create(StringListEditorUiBinder.class);
interface StringListEditorUiBinder extends
UiBinder<Widget, GroupListEditor> {
}
//Gives us access to the event bus.
#Inject private EventBus eventBus;
...
public GroupListEditor() {
initWidget(uiBinder.createAndBindUi(this));
eventBus.addHandler(GroupListUpdatedEvent.TYPE, new GroupListUpdatedEvent.GroupListUpdatedHandler() {
#Override
public void onGroupListUpdatedEvent(GroupListUpdatedEvent event) {
Log.debug("onContainerUpdatedEvent caught");
allGroups = event.getGroupList();
if(allGroups != null) {
for (GroupDTO g : allGroups) {
lbAllGroups.addItem(g.getName(), g.getId().toString());
}
lbAllGroups.setVisibleItemCount(5);
Log.debug("Item list = " + lbAllGroups.getItemCount());
} else {
Log.debug("GROUP LIST is Null!");
}
}
});
}
When i try to register the handler, i get an exception. So i expect the eventBus is not injected properly. What do i miss, how can i use events and the event bus if i am not in a Presenter?
And: Is this the right way at all to populate Editors with "utility" data? I guess Editor should be related directly to the data they care for. But how do i handle this kind of supplemental data?
Thanks :)
Do you use #UiField in your ContainerEditorDialogPresenterWidgetView for your GroupListEditor ?
If so then Dependency Injection won't work because you basically manually create the GroupListEditor which leads to EventBus being NULL.
I would also use Constructor Injection instead of field injection.
GroupListEditor:
#Inject
public GroupListEditor(EventBus eventBus) {
this.eventBus = eventBus;
}
ContainerEditorDialogPresenterWidgetView:
public class ContainerEditorDialogPresenterWidgetView {
#UiField(provided=true)
GroupListEditor groupListEditor;
#Inject
public ContainerEditorDialogPresenterWidgetView(GroupListEditor groupListEditor);
this.groupListEditor = groupListEditor;
initWidget();
}
}
Alternatively you could get an instance of your GroupListEditor via the Ginjector directly.
It's very hard to find questions about GWTP (GWT Platform).
Ok, Here is my Story. I am using GWTP & eclipse to create the Presenter-View structure automatically.
Example, I created a TestPresenter in eclipse, & it created 3 files: TestPresenter.java, TestView.java, TestView.xml
In TestView.xml, i have:
<g:RadioButton ui:field="firstRadioButton" value="false" text="1st" />
<g:RadioButton ui:field="secondRadioButton" value="false" text="2nd" />
<g:RadioButton ui:field="bothRadioButton" value="true" text="Both" />
Now I want to set the GroupName automatically for each TestView, so in TestView.java
public class TestView extends ViewImpl implements
TestPresenter.MyView {
private final Widget widget;
#UiField RadioButton firstRadioButton;
#UiField RadioButton secondRadioButton;
#UiField RadioButton bothRadioButton;
private String groupName;
#UiFactory
RadioButton makeRadioButton() {
return new RadioButton(groupName);
}
public interface Binder extends UiBinder<Widget, TestView> {
}
#Inject
public TestView(final Binder binder) {
widget = binder.createAndBindUi(this);
}
#Override
public Widget asWidget() {
return widget;
}
public RadioButton getFirstRadioButton() {
return firstRadioButton;
}
public RadioButton getSecondRadioButton() {
return secondRadioButton;
}
public RadioButton getBothRadioButton() {
return bothRadioButton;
}
}
In TestPresenter.java,
public class TestPresenter extends
PresenterWidget<TestPresenter.MyView> {
public interface MyView extends View {
public RadioButton getFirstRadioButton();
public RadioButton getSecondRadioButton();
public RadioButton getBothRadioButton();
}
}
Ok, finally I want to use many TestPresenter (by using setInLot) in MainPresenter.java
So, in MainPresenter.java, I have:
public static final Object SLOT1=new Object();
public static final Object SLOT2=new Object();
public static final Object SLOT3=new Object();
public static final Object SLOT4=new Object();
//...... more lot
#Inject TestPresenter testPresenter1;
#Inject TestPresenter testPresenter2;
#Inject TestPresenter testPresenter3;
#Inject TestPresenter testPresenter4;
//.. more test presenter
in MainView.java, i have setInSlot
#UiField HTMLPanel mainHtmlPanel;
#Override
public void setInSlot(Object slot, Widget content){
if(slot==MainPresenter.SLOT1){
mainHtmlPanel.clear();
if(content!=null){
mainHtmlPanel.add(content);
}
}
else if(slot==MainPresenter.SLOT2){
mainHtmlPanel.clear();
if(content!=null){
mainHtmlPanel.add(content);
}
}
//... more else if here
}
Now, if i just do like that then I can not pass the groupName separately for each TestPresenter & that is not good. So I want to pass the groupName string for each TestPresenter so that each will have their own groupName. SOmething like this
#Inject TestPresenter testPresenter1 ("group1");
#Inject TestPresenter testPresenter2 ("group2");
#Inject TestPresenter testPresenter3 ("group3");
#Inject TestPresenter testPresenter4 ("group4");
...
but I don't know how to it properly, so please tell me how to it properly in GWTP?
If you want to specify a groupName in constructors of TestPresenter why you might need to use is assisted injection".
Then you would probably end up with something like this (I have not tested the code):
public interface TestPresenterFactory {
TestPresenter create(String groupName);
}
and in your Gin Module:
#Override
protected void configure() {
...
install(new GinFactoryModuleBuilder().build(TestPresenterFactory.class));
}
Then instead of:
#Inject TestPresenter testPresenter1 ("group1");
#Inject TestPresenter testPresenter2 ("group2");
#Inject TestPresenter testPresenter3 ("group3");
#Inject TestPresenter testPresenter4 ("group4");
...
you would inject the TestPresenterFactory in the constructor of ParentPresenter to create all TestPresenters:
private TestPresenter testPresenter1;
private TestPresenter testPresenter2;
private TestPresenter testPresenter3;
private TestPresenter testPresenter4;
#Inject
public ParentPresenter(final EventBus eventBus, final ParentView view, final ParentProxy proxy, final TestPresenterFactory factory)
{
...
testPresenter1 = factory.create("group1");
testPresenter2 = factory.create("group2");
testPresenter3 = factory.create("group3");
testPresenter4 = factory.create("group4");
}
And the #Assisted annotation in the TestPresenter.java:
public interface MyView extends View {
...
public void setRadioButtonsGroupName(String groupName);
}
#Inject
public TestPresenter(final EventBus eventBus, final MyView view, #Assisted String groupName)
{
...
view.setRadioButtonsGroupName(groupName);
}
And TestView.java:
public class TestView extends ViewImpl implements TestPresenter.MyView {
private final Widget widget;
#UiField RadioButton firstRadioButton;
#UiField RadioButton secondRadioButton;
#UiField RadioButton bothRadioButton;
...
public void setRadioButtonsGroupName(String groupName) {
firstRadioButton.setName(groupName);
secondRadioButton.setName(groupName);
bothRadioButton.setName(groupName);
}
}
But do you really need your TestPresenters to be aware of the groupName used by the RadioButtons in their views ?
Ok, I haven't test Alexis' solution, but his idea of "setGroupName" trigger my mind so I can adjust my code abit & it works fine.
In TestPresenter.java, I have this method
public void setGroupName(String groupName) {
getView().getFirstRadioButton().setName(groupName);
getView().getSecondRadioButton().setName(groupName);
getView().getBothRadioButton().setName(groupName);
}
in MainPresenter.java
#Inject TestPresenter testPresenter1;
#Inject TestPresenter testPresenter2;
....
#Override
protected void onReset() {
super.onReset();
setInSlot(SLOT1, testPresenter1);
setInSlot(SLOT2, testPresenter2);
.....
testPresenter1.setGroupName("group1");
testPresenter2.setGroupName("group2");
....
}
I am trying to add a widget to a panel using UIBinder but the composite simply doesn't load, here is my xml:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:my='urn:import:com.abc.client.test.ui'>
<g:HTMLPanel ui:field="mainLayoutPanel">
<g:SimplePanel ui:field="menuPanel" >
<my:MainMenuViewImpl ui:field="mainMenu"/>
</g:SimplePanel>
<!-- the widget causing the issue -->
<my:FinancialsNav ui:field="nav"/>
<g:SimplePanel ui:field="mainPanel" />
</g:HTMLPanel>
</ui:UiBinder>
The corresponding java class:
public class AppLayoutImpl extends Composite implements AppLayout{
#UiField
HTMLPanel mainLayoutPanel;
interface AppLayoutUiBinder extends UiBinder<Widget,AppLayoutImpl>{}
private static AppLayoutUiBinder binder=GWT.create(AppLayoutUiBinder.class);
#UiField
SimplePanel menuPanel;// nav at the top
#UiField(provided=true)
FinancialsNav nav;// nav on the side
#UiField
SimplePanel mainPanel;// center
#UiField(provided=true)
MainMenuViewImpl mainMenu;
public AppLayoutImpl(ClientFactory clientFactory){
mainMenu=clientFactory.getMainMenuView();
nav=clientFactory.getNav();
initWidget(binder.createAndBindUi(this));
}
#Override
public Widget asWidget(){
return this;
}
}
And the Widget causing the issue:
public class FinancialsNav extends Composite implements ClickHandler{
private VerticalPanel nav=new VerticalPanel();
// Operations
private DisclosurePanel operationsWrapper=new DisclosurePanel(Proto2.constants.financials_navigation_operations());
private NavButton product=new NavButton(Proto2.constants.financials_navigation_products(),
SharedUtilities.PRODUCT_TOKEN);
private NavButton generalOptions=new NavButton(Proto2.constants.financials_navigation_generalOptions(),"");
private ArrayList<NavButton[]> buttons;
private NavButton[] operationsButtons={product,vc,fc,emp,others};
//...
private NavButton[] optionsButtons={generalOptions};
private final EventBus bus;
public FinancialsNav(EventBus bus){
this.bus=bus;
buildNav();
initWidget(nav);
}
private void buildNav(){
buttons=new ArrayList<NavButton[]>();
buttons.add(operationsButtons);
//...
buttons.add(optionsButtons);
int n=buttons.size();
int nn;
for(int i=0;i<n;i++){
nn=buttons.get(i).length;
for(int j=0;j<nn;j++){
(buttons.get(i)[j]).addClickHandler(this);
(buttons.get(i)[j]).setStylePrimaryName(NAV_BUTTON_STYLE);
if(i==0){
operationsWrapper.add(buttons.get(i)[j]);
//...
}else if(i==4){
optionsWrapper.add(buttons.get(i)[j]);
}
}
}
nav.add(operationsWrapper);
// ...
nav.add(optionsWrapper);
}
The FinancialsNav widget works fine when not used with UIBinder and the rest of AppLayout works as expected when the FinancialsNav isn't there.
I spent hours on this looking at various tutorials and examples but simply could not find what is wrong with the code. I also tried various workaround such as declaring a panel in the UIBinder instead of the FinancialsNav and the adding the nav to the panel.
Also everything is in the same package so it shouldn't be an import issue.
Any help would be much appreciated...
Here is the clientFactory
public class ClientFactoryImpl implements ClientFactory{
private static final EventBus eventBus=new SimpleEventBus();
private static final PlaceController placeController=new PlaceController(eventBus);
private static final CreatePlanServiceAsync createPlanService=GWT.create(CreatePlanService.class);
private static final FinancialsNav navView=new FinancialsNav(eventBus);
private static final MainMenuViewImpl mainMenuView=new MainMenuViewImpl();
#Override
public EventBus getEventBus(){
return eventBus;
}
#Override
public PlaceController getPlaceController(){
return placeController;
}
#Override
public FinancialsNav getNav(){
return navView;
}
#Override
public MainMenuViewImpl getMainMenuView(){
return mainMenuView;
}
#Override
public CreatePlanServiceAsync getCreatePlanService(){
return createPlanService;
}
}
FinancialsNav widgets has constructor with arguments. So create no argument constructor.
The entry <my:FinancialsNav ui:field="nav"/> is equals to new FinancialsNav().
In most cases this means that they must be default instantiable; that is, they must provide a zero-argument constructor. you have to pass argument
/** Used by MyUiBinder to instantiate FinancialsNav */
#UiFactory FinancialsNav makeFinancialsNav() { // method name is insignificant. do start with make
return new FinancialsNav(eventBus);
}
Refer Using a widget that requires constructor args
Can you show clientFactory code!!
Ok I found the error, actually not directly related to UIBinder.
Simultaneously to implementing UIBinder I was trying to reduce the number of tables used by the panels in my app.
As I noticed that the disclosure panel is based on a table I removed an intermediary vertical panel I had in the FinancialsNav.
Hence having DisclosurePanel --> Buttons instead of DisclosurePanel --> VerticalPanel --> Buttons. And that is causing the entire block not to show.
#adenoyelle and #bumika: thank you for help
I'm using GWT 2.4 with gwt-platform 0.7 and gin 1.5.0.
I've built a library for dynamic (live) translation of my GWT application. So every widget will get notified when the LocaleChangeEvent gets fired and then ask my TranslationDictionary to get the new String to display.
The widgets actually look like this:
public class LocaleAwareLabel extends Label implements LocaleChangeEventHandler {
TranslationDictionary dictionary;
String translationToken;
public LocaleAwareLabel(TranslationDictionary dictionary, EventBus eventBus, String translationToken) {
this.dictionary = dictionary;
this.translationToken = translationToken;
eventBus.addHandler(LocaleChangeEvent.TYPE, this);
getCurrentTranslationFromDictionary();
}
public void getCurrentTranslationFromDictionary() {
this.setText(dictionary.getTranslation(translationToken));
}
#Override
public void onLocaleChange(LocaleChangeEvent event) {
getCurrentTranslationFromDictionary();
}
}
As you can see: I can't easily use this widget with UiBinder, at the moment I inject EventBus and TranslationDictionary in my View and use #UiField(provided=true)like this:
#UiField(provided=true)
LocaleAwareLabel myLabel;
#Inject
public MyView(TranslationDictionary dictionary, EventBus eventBus) {
widget = uiBinder.createAndBindUi(this);
myLabel = new LocaleAwareLabel(dictionary, eventBus, "someTranslationToken");
}
What I'd like to have: Using my widgets without #UiField(provided=true), so I can simply put them inside a ui.xml like this:
<custom:LocaleAwareLabel ui:field="myLabel" translationToken="someTranslationToken" />
I know I can set the translationToken via UiBinder using:
public void setTranslationToken(String translationToken) {
this.translationToken = translationToken;
}
But then I still have the problem that I can't use a zero-args constructor because of EventBus and TranslationDictionary. And additionaly I can't call the getCurrentTranslationFromDictionary() inside the constructor, because the value of translationToken of course gets set after the constructor.
Would be nice if someone can provide a solution, maybe with code examples.
And P.S. I'm a total injection-noob, but from my understanding gin may somehow solve my problem. But I don't know how.
Thank you!
There's currently a little bit of a concept mismatch between Dependency Injection and UiBinder, but the way I currently use it is:
private final Provider<LocaleAwareLabel> labelProvider;
#Inject
public MyView(TranslationDictionary dictionary,
EventBus eventBus,
Provider<LocaleAwareLabel> labelProvider) {
this.dictionary = dictionary;
this.labelProvider = labelProvider;
initWidget(uiBinder.createAndBindUi(this));
}
#UiFactory
public LocaleAwareLabel buildLocaleAwareLabel() {
return labelProvider.get();
}
Then I can create as many labels as I want in my ui.xml:
<g:HTMLPanel>
<custom:LocaleAwareLabel translationToken="abc"/>
<custom:LocaleAwareLabel translationToken="xyz"/>
</g:HTMLPanel>
In the LocaleAwareLabel, I use a setter method for the translation token, and override onLoad():
private String translationToken;
#Inject
public LocaleAwareLabel(TranslationDictionary dictionary, EventBus eventBus) {
this.dictionary = dictionary;
initWidget(uiBinder.createAndBindUi(this));
}
#Override
protected void onLoad() {
super.onLoad();
doSomethingWithTheTranslationToken(); // do this here, not in the constructor!
}
public void setTranslationToken(final String translationToken) {
this.translationToken = translationToken;
}
Example for AssistedInject
MyView changes to:
private final LocaleAwareLabelFactory labelFactory;
#Inject
public MyView(TranslationDictionary dictionary,
EventBus eventBus,
LocaleAwareLabelFactory labelFactory) {
this.dictionary = dictionary;
this.labelFactory = labelFactory;
initWidget(uiBinder.createAndBindUi(this));
}
#UiFactory
public LocaleAwareLabel buildLocaleAwareLabel(final String translationToken) {
return labelFactory.create(translationToken);
}
LocaleAwareLabel:
public interface LocaleAwareLabelFactory {
LocaleAwareLabel create(final String translationToken);
}
#Inject
public LocaleAwareLabel(TranslationDictionary dictionary,
EventBus eventBus,
#Assisted String translationToken) {
this.dictionary = dictionary;
initWidget(uiBinder.createAndBindUi(this));
doSomethingWithTheTranslationToken(); // now you can do it in the constructor!
}
In your Gin module, add:
install(new GinFactoryModuleBuilder().build(LocaleAwareLabelFactory.class));
Make sure to add guice's assistedinject jar (e.g. guice-assistedinject-snapshot.jar) to your classpath.
This is not possible currently, because UiBinder won't ever call into GIN to instantiate widgets. For that you have to use #UiFactory methods, or provide already-built instances with #Uifield(provided=true).
There's a request for enhancement already to better integrate the two. You can track it here: http://code.google.com/p/google-web-toolkit/issues/detail?id=6151
As an alternative, you can requestStaticInjection to inject a Provider into a static field, and call the provider's get() from within your constructor:
public class LocaleAwareLabel extends Label {
#Inject Provider<EventBus> eventBusProvider;
#Inject Provider<TranslationDictionary> dictionaryProvider;
private final TranslationDictionary dictionary;
private final EventBus eventBus;
private final string translationToken;
#UiConstructor
public LocaleAwareLabel(String translationToken) {
this(dictionaryProvider.get(), eventBusProvider.get(), translationToken);
}
// For cases where you can use injection, or inject params yourself
#Inject
public LocaleAwarelabel(TranslationDictionary dictionary, EventBus eventBus,
String translationToken) {
this.dictionary = dictionary;
this.eventBus = eventBus;
this.translationToken = translationToken;
}
You might also be interested into GIN's support for Assisted-Inject, to make it easier to write #UiFactory methods or initialize #UiField(provided=true) fields.
I'm trying to bind a GWT view with its presentation layer, but it doesn't seem to be doing anything.
It's a Spring Roo GWT generated project and I'm trying to use the scaffold given as far as possible.
The view is a simple button (R.ui.xml) and the rest of the view is defined in R.java:
public class R extends Composite implements RPresenter.Display {
interface MyUiBinder extends UiBinder<Widget, R> {}
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
#UiField Button myButton;
private ClickHandler buttonClickHandler = null;
public R(){
initWidget(uiBinder.createAndBindUi(this));
}
#UiHandler("myButton")
void onButtonClick(ClickEvent event){
GWT.log('Button clicked');
if (buttonClickHandler != null){
GWT.log("buttonClickHandler event triggered");
buttonClickHandler.onClick(event);
}
}
#Override
public void setButtonClickHandler(ClickHandler buttonClickHandler) {
GWT.log("setButtonClickHandler");
this.buttonClickHandler = buttonClickHandler;
}
}
The presenter:
public class RPresenter {
public interface Display extends IsWidget {
void setButtonClickHandler(ClickHandler buttonClickHandler);
}
private final Display display;
private final EventBus eventBus;
#Inject
public RPresenter(EventBus eventBus, Display display){
this.display = display;
this.eventBus = eventBus;
bind();
}
private void bind(){
display.setButtonClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
GWT.log("onClick event triggered");
}
});
}
public void go(HasWidgets container){
container.add(display.asWidget());
}
}
And for my GIN module I use the generated ScaffoldModule in the ...client.scaffold.ioc package:
public class ScaffoldModule extends AbstractGinModule {
#Override
protected void configure() {
GWT.log("ScaffoldModule configure");
bind(EventBus.class).to(SimpleEventBus.class).in(Singleton.class);
bind(ApplicationRequestFactory.class).toProvider(RequestFactoryProvider.class).in(Singleton.class);
bind(PlaceController.class).toProvider(PlaceControllerProvider.class).in(Singleton.class);
//bind(RPresenter.Display.class).to(R.class).in(Singleton.class);
bind(RPresenter.Display.class).to(R.class);
}
static class PlaceControllerProvider implements Provider<PlaceController> {
private final EventBus eventBus;
#Inject
public PlaceControllerProvider(EventBus eventBus) {
this.eventBus = eventBus;
}
public PlaceController get() {
return new PlaceController(eventBus);
}
}
static class RequestFactoryProvider implements Provider<ApplicationRequestFactory> {
private final EventBus eventBus;
#Inject
public RequestFactoryProvider(EventBus eventBus) {
this.eventBus = eventBus;
}
public ApplicationRequestFactory get() {
ApplicationRequestFactory requestFactory = GWT.create(ApplicationRequestFactory.class);
requestFactory.initialize(eventBus);
return requestFactory;
}
}
}
In the GWT development mode console, the "ScaffoldModule configure" never displays, yet the generated scaffold seems to binding just fine as the events get passed along from component to component without a hitch, unless the binding is magically happening somewhere else and that is dead code.
When I put my bind(RPresenter.Display.class).to(R.class) in, it doesn't seem to do the binding. The only output I get in the GWT console is "Button clicked" which is called in the view and then nothing further. I'm clearly missing something, any ideas?
The call to GWT.log() will not output anything from an AbstractGinModule - classes that extend AbstractGinModule (ScaffoldModule in your situation) are used by gin at compile time to decide which concrete implementations to use for injected interfaces. From the rest of your description (i.e. that the UI shows up in the application) it appears that your dependency injection is working correctly.