GWT ClickableTextCell - gwt

I am a newbie to GWT ... need some help in understanding the below class -
What is the use of GWT ClickableTextCell ??
Is there something specific use of it. It uses something called FieldUpdater, why is that used ?

Think of a ClickableTextCell as hot spot. It looks like a regular bit of screen real estate with text in it, but it responds to clicks. What happens when you click it? The click "updates" the field. An update to a field calls the method update(). What does update() do? Whatever you want it to. You provide it by specifying the FieldUpdater. FieldUpdater is an interface, so you can construct one anonymously. Say you have a CellTable, and you have a Column that displays a String inside a ClickableTextCell. You provide your FieldUpdater to the Column:
Column<DataType, String> myIntegerColumn
= new Column<DataType, String>(new ClickableTextCell());
myIntegerColumn.setFieldUpdater(new FieldUpdater<DataType, String>(){
#Override
public void update(int index, DataType object, String value){
// execute code that reacts to a click on this hot spot
}
});
Now whenever the cell gets clicked, that code in update() fires.

A ClickableTextCell is a specific kind of cell. You can see a demo of all the different kinds of cells in this GWT showcase.
This GWT documentation explains what cell widgets are for, goes over all of the different types, and also has examples of how to use them and the ValueUpdater type.

Related

GWT Detect DOM changes or modifications

What am I trying to do?
I have an existing page (generated by system automatically and I don't have any control on it) in which I am injecting GWT code to modify the behaviour of the page after it loads based on certain columns and augment the functionality of the page. For example after adding my GWT code, cells in one of the table columns become clickable and when the user clicks it, additional information is displayed to the user in a pop-up panel. All that is working fine.
What is the issue?
The generic page in which I am injecting my code has paginated table which shows 15 rows at a time. Now, when I load/refresh the page, my GWT code kicks in and sinks events in the specific column which adds functionality (described above) to the cells. However, when the user uses the left and right buttons to navigate the paginated result, the page does not refresh as it is an asynchronous call. The specific column in the new set of 15 rows is now without the sunk events as the GWT code does not know that the page changed.
I am trying to find a way to tell my GWT code that page has changed and it should sink events to the cells of specific column for the new 15 rows but unable to find any method or mechanism to help me capture a DOM/Document change event. I tried doing this but did not help:
new ChangeHandler(){
#Override
public void onChange(ChangeEvent event) {
Window.alert("Something Changed");
}
It is possible I am missing something very obvious. Posting this question to know if there is an easy way to figure out DOM changes in GWT. Have searched for DOM/Document change/mutation/ etc. without luck.
If anyone knows how to detect DOM changes in GWT would really appreciate otherwise would go ahead writing native code using native mutation observers.
You can try something like this:
First get the input elements with:
InputElement goOn = DOM.getElementById("IdOfGoOnButton").cast();
InputElement goBack = DOM.getElementById("IdOfGoBackButton").cast();
Next add a native EventHandler:
Event.addNativePreviewHandler(new Event.NativePreviewHandler() {
#Override
public void onPreviewNativeEvent(Event.NativePreviewEvent event) {
if (event.getTypeInt() == Event.ONCLICK) {
if (event.getNativeEvent()
.getEventTarget() != null) {
Element as = Element.as(event.getNativeEvent()
.getEventTarget());
if (as.getTagName()
.toLowerCase()
.equals("input")) {
InputElement clickedElement = as.cast();
if (clickedElement.getId().equals(goOn.getId()) ||
clickedElement.getId().equals(goBack.getId())) {
// one of the paging button is pressed
}
}
}
}
}
});
Hope that helps.

GWTP: Correct information flow for popup presenter

i had this task: I have Presenter/View Couple (lets call it ItemListPresenter) showing a Celltable. Now i wanted to edit an item by double-clicking it (or pressing a button, whatever). Then a popup dialog should appear (Lets call it PopupWidget), letting me edit my item properties.
i found a solution how to do it, but i am not sure it is the "right" way. Since i am trying to learn the philosophy behind GWT/GWTP, i would appreciate if you could give me hints what i did right and what i did wrong:
In the onbind method of ItemListPresenter, i wire the CellTable with a DoubleClick handler:
getView().getCellTable().setSelectionModel(selectionModel);
getView().getCellTable().addDomHandler(new DoubleClickHandler() {
#Override
public void onDoubleClick(final DoubleClickEvent event) {
DeviceDto selectedDeviceDto = selectionModel.getSelectedObject();
//TODO: Figure out how to best handle editing of DeviceDto
if (selectedDeviceDto != null) {
devicesDialog.setCurrentDeviceDTO(selectedDeviceDto);
addToPopupSlot(devicesDialog);
}
} }, DoubleClickEvent.getType());
What does not feel right is setting the object i want to edit (selectedDeviceDto) in the Dialog Presenter Widget. Is this the "right" way?
My popup presenter which is defined as
public class DeviceEditDialogPresenterWidget extends PresenterWidget<DeviceEditDialogPresenterWidget.MyView> implements
DeviceEditDialogUiHandlers {
is still ugly, since i just set every property into a text box and after editing, i recollect the properties and rebuild the object. This is messy and i guess i should GWT Editors for that. However, when i click the "Save" Button in the dialog, an UiHandler is triggered:
#UiHandler("okButton")
void okButtonClicked(ClickEvent event) {
DeviceDto dev = new DeviceDto(idBox.getText(), deviceIdBox.getText(), typeBox.getText(), firmwareVersionBox.getText(), userBox.getText(), statusBox.getText());
getUiHandlers().updateDevice(dev);
hide();
}
This triggers my DeviceEditDialogPresenterWidget, which itself fires and event:
#Override
public void updateDevice(DeviceDto device) {
eventBus.fireEvent(new DeviceUpdatedEvent(device));
}
This event is caught by a handler in the "mother" presenter with the CellTable, which is wired in the onBind method again:
addRegisteredHandler(DeviceUpdatedEvent.TYPE, new DeviceUpdatedEvent.DeviceUpdatedHandler() {
#Override
public void onDeviceUpdatedEvent(DeviceUpdatedEvent event) {
updateDevice(event.getDevice());
}
});
I would really like to avoid going down a road of messy mistakes, so any hints would be appreciated.
Thanks
Arthur
PresenterWidgets are usually designed to have a setter which is used to set a Model or DTO that the PresenterWidget works on (the same way you did it).
Alternatively you can avoid a PresenterWidget and use an Editor (extends Composite) that you manually add to a PopupPanel or DialogBox in your ListItemEditor.
This way you avoid the complexity of a PresenterWidget. But you have to handle the clicks (i.e. save button) from the ListItemPresenter. I would always try to start small (use a composite) and if you realize that you might need the functionality also in other places, create a PresenterWidget.
Also you don't need the updateDevice method because you pass a reference to your DTO. You only need to fresh the CellTable.
But apart from that your approach looks fine.

GWT: How to run code after sorting a datagrid column

I really need a possibility to run some code after the whole sorting of the DataGrid is finished. Especially after the little arrow which shows if the column is sorted ascending or descending is displayed, because i need to manipulate the CSS of this arrow after it is displayed. I couldn't find the place where the arrow is really set. I tried something like this:
ListHandler<String> columnSortHandler = new ListHandler<String>(list) {
#Override
public void onColumnSort( ColumnSortEvent event ) {
super.onColumnSort( event );
// My Code here
}
};
but the code runs also before sorting finishes.
Thanks for any suggestions how to solve this problem. I am searching for a long time now but cannot find anything that helps.
EDIT: I already override the original DataGrid.Resources to provide a custom arrow-picture. I also have a complex custom header of AbstractCell<String> which supports runtime-operations and is rendered with DIV's and Image.
As you're using a ListHandler, and thus probably a ListDataProvider that will update the CellTable live (setRowData); because both ListDataProvider and CellTable (via the inner HasDataPresenter) use Scheduler#scheduleFinally(), then using Scheduler#scheduleDeferred() should be enough to guarantee that you run after them, but then you'll risk some flicker.
You could, in your custom ListHandler flush() the ListDataProvider, which will bypass one scheduleFinally and then use scheduleFinally to execute after the one of the CellTable (because flush() will call setRowData on the CellTable which will schedule the command; your command wil be scheduled after, so will run after).
You can manipulate the css resource using CellTable.Resources.
public interface TableResources extends CellTable.Resources {
#Source("up.png")
ImageResource cellTableSortAscending();
#Source("down.png")
ImageResource cellTableSortDescending();
#Source("MyCellTable.css")
CellTable.Style cellTableStyle();
}
In MyCellTable.css use the stylename and change your icon

GWT Widget not properly set in the DOM

I would like to print a GWT widget which extends Composite. This widget is composed of a grid whose cells are built with a ListDataProvider. When the user clic on a button print, the widget to print is built. Once this is done, I launch the print:
Element element = widgetToPrint.getElement();
String content = element.getInnerHTML();
print(content);
public static native boolean print(String content)
/*-{
var mywindow = window.open('', 'Printing', '');
mywindow.document.write('<html><head><title>Test</title>');
mywindow.document.write('<link rel="stylesheet" href="/public/stylesheets/ToPrintWidget.css" type="text/css" media="all"/></head><body>');
mywindow.document.write(content);
mywindow.document.write('</body></html>');
mywindow.print();
return true;
}-*/;
So, here is my problem:
The window which is opened by this method contains the core of the widget (built by the UI Binder), but some children are missing...
If I look inside the ListDataProvider and its related FlowPanel, the data are consistent, i.e. I've got several item in my list and in the flowPanel.
Consequently, it should be visible on the printing window...
I thought that maybe the problem was related to the method used to print the widget, so I also tried to add this widget into a dialogbox just before launching the print, to see if the widget was properly built... and it was.
So my widget displays well on a dialogbox, but if I try to give its innerHTML to the print method, by using getElement(), some widgets are missing... I've the feeling that the widgets which should have been built when the ListDataProvider changes are not properly set in the DOM... Somehow it works when I add the widget to a regular component, but it doesn't work when I have to give directly its innerHTML...
Do you have any idea ?
Thanks in advance.
Widgets are not just the sum of their elements, and DOM elements are not just the string that they are serialized to. Widgets are the element, and all events sunk to the dom to listen for any changes or interactions by the user. Elements then have callback functions or handlers they invoke when the user interacts with them.
By serializing the element (i.e. invoking getInnerHTML()), you are only reading out the structure of the dom, not the callbacks, and additionally not the styles set by CSS. This probably shouldn't be expected to work correctly, and as your experience is demonstrating, it doesn't.
As this is just a print window you are trying to create, event handling is probably not a concern. You just want the ability to see, but not interact with, the content that would be in that set of widgets. Styles are probably the main problem here then (though your question doesn't specify 'some children are missing' doesn't tell us what is missing, or give us any more clues as to why...) - you are adding one stylesheet in your JSNI code, but CellTable (which I assume you are using since you reference ListDataProvider) needs additional CssResource instances to appear correctly. I'm not sure how you can hijack those to draw in a new window.
Are you only using this to print content, not to let the user directly interact with the data? If so, consider another approach - use a SafeHtmlBuilder to create a giant, properly escaped string of content to draw in the new window.
String content = element.toString();
This will include all hierarchy elements in the node.
Just a reminder, all the GWT handlers will not work, and you have to sink all the events using DOM.
You might want to grab the outer HTML rather than the inner one.
GWT unfortunately has no getOuterHTML, but it's relatively easy to emulate.
If your widget is the only child within an element, then simply get the inner HTML of the parent element (w.getElement().getParentElement().getInnerHTML())
Otherwise, clone your widget's node add it to a newly created parent element, from which you'll be able to get the inner HTML:
DivElement temp = Document.get().createDivElement();
temp.appendChild(w.getElement().cloneNode(true));
return temp.getInnerHTML();
First thank you for your answers, it helped me to work out this problem.
I've almost solve the problem:
First, I do not use ListDataProvider anymore, because it wasn't clear for me when and how the view was refreshed. Instead I add my widgets by hand, which makes sense since, they are not going to move anyway.
Then, I define the style of my widgets using a common CSS stylesheet. However, in order to do it, I can't rely on CssResource, which was the way I was used to do it with GWT. I think that this comes from the JS method which gets lost by this kind of styles... Instead, I have to specify everything in a static CSS stylesheet, and to give it to the JS.
It works perfectly well, ie, I have my widgets, with thei styles, and I can print it.
But...
The color of some widgets depends on the color of the object that they represent. Consequently, I cannot write a generic CSS stylesheet... And as I said, I can't add a style using CssResource... Do you have any ideas on the way to handle that ?
To make sure I'm clear on the way I'm adding styles, here is an example:
Label l = new Label("Here is a cell in my grid to be printed");
l.addStyleName("PrintLineCell-kind_1");
With, in a public CSS stylesheet:
.PrintLineCell-kind_1{
background-color: red;
}
I hope there is a better way than to write 300 styles to cover 300 different colors...

Dynamcially adding panels based on DropdownChoice selection

am a newbie to wicket and am experimenting few things with it, like, I have four panel but one only should be added based on the selection made in the DropdownChoice component.
i tried to add panels using onSelectChange() method, but it doesn't work. can any one please help me out with proper sample code.
I give you an example for this problem. Hope it helps.
DropDownChoice dropDown = new DropDownChoice(...........);
AjaxFormComponentUpdatingBehavior behavior = new AjaxFormComponentUpdatingBehavior(
"onchange") {
#Override
protected void onUpdate(AjaxRequestTarget target) {
//you should write here the logic that
// replaces the panel, something like: content.addOrReplace(panel)
target.addComponent(form);
}
};
dropDown.add(behavior);
So that's all, you have to use AjaxFormComponentUpdatingBehavior to handle onchange event. If the dropdown menu not a requirement, you can use tabbedpanel. Here you can find the sample code: wicket tabbed panel