Injecting Handlers in Custom Widget - gwt

I have a handler classes, I need to inject it in the custom widgets.
I tried the bind() method in ClientModule class, but it is not getting injected.
What am I supposed to do, do get the class injected.
public class ExtendedTextBoxBase extends TextBox {
public ExtendedTextBoxBase() {
super.addBlurHandler(textBoxBlurHandler);
}
#Inject
TextBoxBlurHandler textBoxBlurHandler; /* custom handler */
}
custom handler:
public class TextBoxBlurHandler implements BlurHandler {
#Inject
public TextBoxBlurHandler() {
}
#Override
public void onBlur(BlurEvent event) {
}
}
Thanks,
Bennet.

Initial reaction: did you include and #Inject statement in the method (likely constructor) where you would like to inject the handler?
If yes: could you be more specific with some code snippets?

I see two potential errors:
1. You have code in constructor:
super.addBlurHandler(textBoxBlurHandler);
so you should inject handler by constructor not by field.
Gin first crate object than inject fields into class, so your handler textBoxBlurHandler is null.
2. You crate your ExtendedTextBoxBase by uibinder. If yes, you should add annotation uiField provided=true, and inject this field:
#Inject
#UiField(provided=true)
ExtendedTextBoxBase extendedTextBoxBase;

Related

GWTP get access from child presenter/view to parent presenter/view

I have 2 presenters/view. Lets call them parent and child. parent presenter is a container (using slot mechanism) for the child presenter.
In the child presenter's view user clicked button and I would like to handle this action in parent presenter.
How can I do this? What is the best approach? Should I use some kind of event and eventhandler? Or should I inject one presenter to the other?
Both are possible.
For events - GWTP have a simplified version of GWT events:
public interface MyEventHandler extends EventHandler {
void onMyEvent(MyEvent event);
}
public class MyEvent extends GwtEvent<MyEventHandler> {
public static Type<MyEventHandler> TYPE = new Type<MyEventHandler>();
private Object myData;
public Type<MyEventHandler> getAssociatedType() {
return TYPE;
}
protected void dispatch(MyEventHandler handler) {
handler.onMyEvent(this);
}
public MyEvent(Object myData) {
this.myData = myData;
}
/*The cool thing*/
public static void fire(HasHandlers source, Object myData){
source.fireEvent(new MyEvent(myData));
}
}
So in your child presenter you'll simply do:
MyEvent.fire(this, thatObjectYoudLikeToPass);
and to register it, in the parent, you'd either use:
addRegisteredHandler(MyEvent.TYPE, handler);
or
addVisibleHandler(MyEvent.TYPE, handler);
if you want it to be processed only when the parent is visible. I suggest you yo add these handlers in onBind method of your presenter (don't forget to call super.onBind() first when overriding)
For injection:
Simply make sure:
Your parent presenter is a singleton
To avoid circular dependency error in GIN do not wire it like
#Inject ParentPresenter presenter;
instead do it like this:
#Inject
Provider<ParentPresenter> presenterProvider;
and access it with presenterProvider.get() in your child

how to inject a uiBinder with #Inject (instead of GWT.create())?

Firstly, is doing such thing a good practice ?
I tried what seems to be the right way for me but wasn't successful :
public class FormViewImpl extends CompositeView implements HasUiHandlers<C>, FormView {
public interface SettlementInstructionsSearchFormViewUiBinder extends UiBinder<Widget, SettlementInstructionsSearchFormViewImpl> {}
#Inject
static FormViewImpl uiBinder;
#Inject
static Provider<DateEditorWidget> dateEditorProvider;
#UiField(provided = true)
MyComponent<String> myComp;
#UiField
DateEditorWidget effectiveDateFrom;
// .. other fields
#Inject
public FormViewImpl () {
myComp = new MyComponent<String>("lol");
if (uiBinder == null)
uiBinder = GWT.create(SettlementInstructionsSearchFormViewUiBinder.class);
initWidget(uiBinder.createAndBindUi(this));
}
#UiFactory
DateEditorWidget createDateEditor() {
return dateEditorProvider.get();
}
}
What other things than a class with no arguments is required ? In my company's project the same kind of code works at some other place. Sorry from the high level of noob here...
If you guys had any pointers it would be nice.
Thanks
Two issues:
First, two of your #Inject fields are static - have you done anything to make static fields be injected? Static fields don't get set when Gin (or Guice) creates new instances, those have to be set once and done. As they are static, they will never be garbage collected - this may be okay with you, or it might be a problem, and you should change them to instance fields. If you want to keep them static, then you must invoke requestStaticInjection in your module to ask Gin to initialize them when the ginjector is created.
Next, if you do choose to remove static, the uiBinder field must still be null in that constructor, because the fields can't have been injected yet! How do you set a field on an object that you haven't yet created? That's what you are expecting Gin to be able to do. Instead, consider passing that as an argument into the #Inject decorated constructor. You don't even need to save it as a field, since the widget will only use it the one time.
To have a class generated by GIN (doesn't matter if it is a uiBinder or not) it is not necessary for it to have a default constructor (i.e. the one without parameters). The class you want to inject must have the constructor annotated with #Inject:
#Inject
public InjectMeClass(Object a, Object b)
The other class which is injected, suppose it is a UiBinder, must have the injected fields annotated with #UiField(provided=true):
public class Injected extends Composite {
private static InjectedUiBinder uiBinder = GWT
.create(InjectedUiBinder.class);
interface InjectedUiBinder extends UiBinder<Widget, Injected> {
}
#UiField(provided=true)
InjectMeClass imc;
public Injected(final InjectMeClass imc) {
this.imc=imc;
initWidget(uiBinder.createAndBindUi(this));
}
So, back to your case:
#UiField(provided = true)
MyComponent<String> myComp;
#Inject
public FormViewImpl (MyComponent<String> myComp) {
this.myComp = myComp;
and for example:
public class MyComponent<T> extends Composite {
private T value;
#Inject
public MyComponent(T t) {
this.value = t;
...
}
...
}
In the GIN module you can have a provider:
#Provides
#Singleton
public MyComponent<String> createMyComponent() {
return new MyComponent<String>("lol");
}

GWT Null objects in #UiHandler methods

I am using GWT 2.4 with MVP.
Here is my view object:
public class LoginWidget extends Composite implements LoginWidgetView {
interface Binder extends UiBinder<Widget, LoginWidget> {
}
private static final Binder BINDER = GWT.create(Binder.class);
#UiField Anchor settings;
public LoginWidget() {
initWidget(BINDER.createAndBindUi(this));
}
#UiHandler("settings")
void handleSettingsClick(ClickEvent e) {
presenter.showSettings();
}
private Presenter presenter;
#Override
public void setPresenter(Presenter presenter) {
this.presenter = presenter;
}
}
I am setting the view´s presenter by
...
getLoginWidget().setPresenter(new LoginWidgetPresenter(placeController));
LoginWidgetPresenter of course implements the view´s Presenter interface. But when I click on the settings anchor, the presenter reference is still null, so presenter.showSettings() throws a NullPointerException.
I suppose that after calling the LoginWidget´s constructor and initializing the widget by
initWidget(BINDER.createAndBindUi(this));
the click handling code in my #UiHandler("settings") method ignores changes to the used objects like my presenter object??
Is there a way to set the presenter object after calling the initWidget() method?
Or is it possible to customize the #UiHandler/initWidget()-behaviour that I can set my presenter afterwards?
Thanks, Manuel
I implement MVP in another way and UIBinder work for my. Maybe if you pass the LoginWidgetPresenter in LoginWidget constructor it works.
public LoginWidget(Presenter presenter) {
this.presenter = presenter;
initWidget(BINDER.createAndBindUi(this));
}
...
getLoginWidget(new LoginWidgetPresenter(placeController));
There are lot of things, which could have gone wrong. The easiest thing is to try to debug your code, by putting breakpoints handleSettings and 'setPresenter' methods.
My guess is that one of following is happening:
setPresenter is never actually called
or
getLoginWidget() always returns a new instance of the widget, and it is quite possible that you are setting presenter on one instance of login widget, but displaying totally different instance of the widget
or
You have getLoginWidget().setPresenter(null) somewhere in your code
or any other guess. It is much more easier to debug, and see for yourself, where and how presenter instance is passed. Anyway, UiBinder will not erase your field values (unless it is modified by someone else to make fun of you)

Error binding view to presenter?

I'm getting this error when running GWT application:
java.lang.AssertionError: This UIObject's element is not set; you may be missing a call to either Composite.initWidget() or UIObject.setElement()
public class MainView extends Composite implements HeaderPresenter.MyView {
// Code omitted
}
In the Gin ClientModule.java configure() function I have this code:
bindPresenter(HeaderPresenter.class, HeaderPresenter.MyView.class,
MainView.class, HeaderPresenter.MyProxy.class);
In the view class the initWidget() is properly called and passed with a widget, what could be causing the error?
This error occurs when UIObject.setElement isn't called. If you are calling Composite.initWidget with a non-null widget, make sure that that widget is setting its own element correctly. If this is a standard GWT widget, it should be doing that, but otherwise it is possible that the widget passed to initWidget isn't set up correctly.
This is how I create a Composite that I will use later in a View.
public class MyCustomBox extends Composite {
private static MyCustomBoxUiBinder uiBinder = GWT.create(MyCustomBoxUiBinder.class);
interface MyCustomBoxUiBinder extends UiBinder<Widget, MyCustomBox> {
}
public MyCustomBox() {
initWidget(uiBinder.createAndBindUi(this));
}
}

GWT: how to fire custom events from View and consumed by Activity

I can't make a custom event be received in the Activity. Can anyone please tell me what am I missing? I am using GWT 2.1, MVP pattern and UiBinder.
Here's a sample of what I wrote:
Let's say I have MyCustomEvent class and its handler interface MyCustomEventHandler with its onMyCustomEvent(MyCustomEvent event) method.
I implement the handler interface in the Activity:
class MyActivity extends AbstractActivity implements MyCustomEventHandler {
....
public void onMyCustomEvent(MyCustomEvent event) {
doWhatYouKnow();
}
//EventBus is injected with GIN
public void start(AcceptsOneWidget container, EventBus eventBus) {
...
eventBus.addHandler(MyEvent.TYPE, this);
}
}
Now, the sending part in the view:
public class MyWidget extends Composite {
final PopUpPanel myPopUp;
public MyWidget() {
initWidget(uiBinder.createAndBindUi(this));
myPopUp.addCloseHandler(new CloseHandler<PopupPanel>() {
#Override
public void onClose(CloseEvent<PopupPanel> event) {
MyEvent event = new MyEvent();
fireEvent(event);
}
});
}
}
No exception are thrown and unfortunately onMyCustomEvent is never called in the MyActivity class. Any idea? Thanks a million.
#MyWidget
you can make the constructor take parameter ( eventBus )
which you can pass this from class MyActivity
so when you fire the event #MyActivity
the action will be executed #MyWidget
try this , i think it will work .
I think one of your comments is pointing you in the right direction here. What I'm going to guess is going on is that you have more than one EventBus floating around (there should usually only be one event bus per application).
First of all, make sure the EventBus in your Gin module is bound in the Singleton scope. Also, make sure this is the event bus that you pass in to your PlaceController, and not one you're constructing on your own.
Also, I wouldn't be too worried about the fact that your object is a ResettableEventBus in one place. I believe that's just an object that's created by the Activities/Places framework that just wraps the EventBus object you give it.