GWT's Editor Framework and GWTP - gwt

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

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

UiEditor/RequestFactory generate null delegate on ValueProxy

I have a Service.class ValueProxy in a service oriented architecture (i have a server method like "storeService(service)".
I would use an Editor with RequestFactoryEditorDriver.
I expect all work, but when i call driver.edit(service) i get a null delegate exception.
Why? It's a bug?
At http://crazygui.wordpress.com/tag/editor/ i find a sample of implementation...only differece with mine is SimpleBeanRequestEditorDriver.class (i have RequestFactoryEditorDriver.class)
ServiceEditor.class
public class ServiceEditor extends Composite implements Editor<ServiceProxy>{
private static final Logger logger = Logger.getLogger(ServiceEditor.class.getName());
private static ServiceEditorUiBinder uiBinder = GWT
.create(ServiceEditorUiBinder.class);
interface ServiceEditorUiBinder extends
UiBinder<Widget, ServiceEditor> {
}
//~Driver ==========================================================================================================================
interface Driver extends RequestFactoryEditorDriver<ServiceProxy, ServiceEditor> {
}
Driver driver;
//====================================================================================================================================
#UiField
Decorator<String> name;
#UiField
Decorator<String> description;
#UiField
Decorator<String> notes;
#UiField
Decorator<String> citiesString;
// #UiField(provided=true)
// Decorator<String> category;
// MultiWordSuggestOracle oracle = new MultiWordSuggestOracle();
// #UiField(provided=true)
// #Ignore
// SuggestBox suggestBox = new SuggestBox(oracle);
private BigInteger organizationId;
private EditorDelegate<ServiceProxy> delegate;
public ServiceEditor() {
initWidget(uiBinder.createAndBindUi(this));
driver = GWT.create(Driver.class);
}
#Override
protected void onLoad() {
driver.initialize(ClientFactory.AppInjector.getRequestFactory(),this);
}
public void edit() {
ServiceRequestContext requestContext = ClientFactory.AppInjector.getRequestFactory().getNewServiceContext();
edit(requestContext.create(ServiceProxy.class),requestContext);
}
public void display(ServiceProxy p){
driver.display(p);
}
public void edit(ServiceProxy p) {
ServiceRequestContext requestContext = ClientFactory.AppInjector.getRequestFactory().getNewServiceContext();
edit(p,requestContext);
}
public void edit(ServiceProxy service,ServiceRequestContext requestContext) {
if(service.getToken()==null) {
requestContext.addServiceToOrganization(organizationId, service);
//TODO: attenzione a tempistiche chiamate;
SessionRPC.Util.getInstance().getOrganizationId(new AsyncCallback<BigInteger>() {
#Override
public void onSuccess(BigInteger result) {
organizationId = result;
}
#Override
public void onFailure(Throwable caught) {
}
});
}
else
requestContext.updateService(service);
driver.edit(service,requestContext);
}
public RequestContext flush2(){
return driver.flush();
}
public void submit(Receiver<Void> receiver){
RequestContext context = driver.flush();
if (driver.hasErrors()) {
Window.alert("Driver errors!");
return;
}
context.fire(receiver);
}
public void notifyErrors(Set<ConstraintViolation<?>> violations) {
driver.setConstraintViolations(violations);
//driver.getErrors().get(0).
logger.info("Validation Errors: /n "+driver.getErrors().toString());
}
// #Override
// public void setDelegate(EditorDelegate<ServiceProxy> delegate) {
// this.delegate = delegate;
// }
}
ActivitySnippet...
ServiceEditor serviceEditor = GWT.create(ServiceEditor.class);
serviceEditor.display(response);
Stack trace...
Caused by: com.google.gwt.core.client.JavaScriptException: (TypeError) : Cannot set property 'request' of undefined
at Unknown.$collect(JsArrayString.java:42)
at Unknown.fillInStackTrace_2(StackTraceCreator.java:180)
at Unknown.fillInStackTrace_0(StackTraceCreator.java:518)
at Unknown.fillInStackTrace(Throwable.java:115)
at Unknown.Throwable_0(Throwable.java:51)
at Unknown.Exception_0(Exception.java:25)
at Unknown.RuntimeException_0(RuntimeException.java:25)
at Unknown.JavaScriptException_1(JavaScriptException.java:117)
at Unknown.JavaScriptException_0(JavaScriptException.java:109)
at Unknown.getCachableJavaScriptException(Exceptions.java:45)
at Unknown.wrap(Exceptions.java:29)
at Unknown.$setRequestContext(RequestFactoryEditorDelegate.java:80)
at Unknown.$edit(AbstractRequestFactoryEditorDriver.java:168)
at Unknown.display_0(AbstractRequestFactoryEditorDriver.java:159)
at Unknown.$show_2(ServiceEditor.java:91)
This means that getDelegate() method (line 168 of AbstractRequestFactoryEditorDriver.class) return null.
If you call RequestFactoryEditorDriver.show, it essentially just calls RequestFactoryEditorDriver.edit, but without a requestcontext. This otherwise should follow the same basic path in terms of how the driver needs to be wired up.
In this case, if the delegate is null, then the driver hasn't been initialized. From your code:
public ServiceEditor() {
initWidget(uiBinder.createAndBindUi(this));
driver = GWT.create(Driver.class);
}
#Override
protected void onLoad() {
driver.initialize(ClientFactory.AppInjector.getRequestFactory(),this);
}
public void edit() {
ServiceRequestContext requestContext = ClientFactory.AppInjector.getRequestFactory().getNewServiceContext();
edit(requestContext.create(ServiceProxy.class),requestContext);
}
public void display(ServiceProxy p){
driver.display(p);
}
You never listed the code that shows when edit or display are being called, so I'm mostly guessing here, but it looks like your other code looks roughly like this:
ServiceEditor editor = new ServiceEditor();//create ui, create driver.
editor.display(data);//driver.display, which calls driver.edit
parentWidget.add(editor);// causes onLoad to be called if actually
//attached to the dom, which causes driver.initialize
This is wrong. The driver must be initialized before you attempt to edit or display, since otherwise it doesn't know which editor objects it should be working with.
Instead, move driver.initialize to earlier than onLoad, like in the ServiceEditor constructor itself, or in some init method which allows you to call it earlier deliberately. Another option is to just call parent.add(editor) before editor.display(), though this may not work - make sure you understand what causes onLoad to be called.
(Please note that ServiceEditor.show is in your stack trace but not in your code listing, so I can't tell if the chance would be more obvious in seeing this.)

How to pass additional data to GWT sub-editors?

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.

GWT Platform UiHandlers not working

I have followed the GettingStarted on the GWTP tutorial
http://code.google.com/p/gwt-platform/wiki/GettingStarted
but unfortunately handlers not working, getUiHandlers() return null and exception stacktrace is same as in:
How to use UiHandlers of GWT Platform?
.
View Class
public class AView extends ViewWithUiHandlers<AUiHandlers> implements APresenter.Display {
#UiTemplate("AView.ui.xml")
interface AViewUiBinder extends UiBinder<Widget, AView> {}
private static AViewUiBinder uiBinder = GWT.create(AViewUiBinder.class);
#UiField Button saveBtn;
#UiField Button cancelBtn;
#UiField DivElement errorDiv;
private Widget widget;
#Inject
public AssetView() {
widget = uiBinder.createAndBindUi(this);
}
public Widget asWidget() {
return widget;
}
// Implementation: Presenter's Display methods
public void setErrorDivText(String msg) {
errorDiv.getStyle().setDisplay(Display.BLOCK);
errorDiv.setInnerText(msg);
}
// Handlers
#UiHandler("saveBtn")
void onSaveButtonClick(ClickEvent event) {
if(getUiHandlers() != null) {
getUiHandlers().onSaveButtonClick();
}
}
#UiHandler("cancelBtn")
void onCancelButtonClick(ClickEvent event) {
if(getUiHandlers() != null) {
getUiHandlers().onCancelButtonClick();
}
}
}
Handler Interface
public interface AUiHandlers extends UiHandlers {
void onSaveButtonClick();
void onCancelButtonClick();
}
Presenter
public class APresenter extends Presenter<APresenter.Display, APresenter.AssetProxy> implements AUiHandlers {
public interface Display extends View, HasUiHandlers<AUiHandlers> {
public void setErrorDivText(String msg);
}
#ProxyStandard
#NameToken(NameTokens.ASSET)
public interface AssetProxy extends ProxyPlace<AssetPresenter> {}
#Inject
public AssetPresenter(EventBus eventBus, Display view, AssetProxy proxy) {
super(eventBus, view, proxy);
getView().setUiHandlers(this);
}
#Override
protected void onBind() {
super.onBind();
}
#Override
protected void revealInParent() {
RevealRootContentEvent.fire( this, this );
}
public void onSaveButtonClick() {
getView().setErrorDivText("Save clicked.");
}
public void onCancelButtonClick() {
getView().setErrorDivText("Cancel clicked.");
}
}
Unable to understand where i am making mistake, implementation regarding UiHandlers is same as told in the above mentioned tutorial's link.
UiHandlers is not generic; it cannot be parameterized with arguments
As I see your handler interface, you have passed AUiHandlers type. I don't understand the package structure of UiHandlers . it should be com.gwtplatform.mvp.client.UiHandlers.
Please check import of it.
Update:
Remove private static AViewUiBinder uiBinder = GWT.create(AViewUiBinder.class);
and Pass as constructor argument
#Inject
public AssetView(AViewUiBinder uiBinder) {
widget = uiBinder.createAndBindUi(this);
}

GIN & GWT: Binding Presentation layer with View

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.