Form element values not binding in custom input cell (using AbstractInputCell)

61 views
Skip to first unread message

sevendays

unread,
Dec 3, 2010, 9:23:25 AM12/3/10
to Google Web Toolkit
I have created a CellBrowser where each cell is a custom HTML
component that features a few different HTML form components (e.g.
age, feeling etc.).

The form displays fine, however, I can't get the value entered in the
form into the client-side code. The relevant element in the DOM
doesn't have the 'value' attribute set properly.

I have tried a few things, including:

1) Getting the element from the DOM object using
dom.getElementById(ELEMENT_AGE_ID), this returns an entity but value
is null, even though I had just entered a value into this element.

2) Recursively looping round the DOM node tree, and printing it out to
the console (printElementTree()) - again I can see the element but the
value is null (after entering a value).


What am I not doing correctly? How can I get the value attribute to
update on the element in the DOM? Once it has been updated, how do I
get the values from the elements with IDs ELEMENT_AGE_ID,
ELEMENT_FEELING_ID etc.?

An extract of the code is below. Any suggestions or advice would be
appreciated.

---------------------------------------------------

public class NodeTreeItemCell extends AbstractInputCell<NodeDTO,
NodeTreeItemCell.ViewData> {

public static final int CELL_WIDTH = 440;

// these statics are the HTML element IDs
public static final String ELEMENT_AGE_ID = "txtAge";
public static final String ELEMENT_FEELING_ID = "optFeeling";
public static final String ELEMENT_TOWN_ID = "txtTown";
public static final String ELEMENT_BUTTON_UPDATE_ID = "btnUpdate";

public NodeTreeItemCell() {
/*
* Let the parent class know that our cell responds to click events
and
* keydown events.
*/
super("click", "change", "keyup");

}


@Override
public void render(NodeDTO value, Object key, SafeHtmlBuilder sb) {

if (value == null) {
return;
}

// Start
sb.appendHtmlConstant("<div id=\"hPanelRoot\" class=\"nbRoot\" >");
sb.appendHtmlConstant(" <table>");
sb.appendHtmlConstant(" <tr>");

// left panel
sb.appendHtmlConstant(" <td style=\"vertical-align:top;\" id=
\"vPanelLeft\">");
sb.appendHtmlConstant(" <table>");
sb.appendHtmlConstant(" <tr><td class=\"nbIcon\">*</td></tr>");
sb.appendHtmlConstant(" </table>");
sb.appendHtmlConstant(" </td>");

// main panel
sb.appendHtmlConstant(" <td style=\"vertical-align:top;\" id=
\"vPanelMain\" class=\"nbMainPanel\">");
sb.appendHtmlConstant(" <table style=\"width:100%;\">");
sb.appendHtmlConstant(" <tr>");
sb.appendHtmlConstant(" <td>");
sb.appendHtmlConstant(" <span>Build:</span>");
sb.appendHtmlConstant(" <input type=\"text\" class=\"nbTextBox\"
size=\"3\" maxlength=\"3\" id=\"" +
SafeHtmlUtils.fromTrustedString(ELEMENT_AGE_ID) + "\"></input>");
sb.appendHtmlConstant(" <span>%</span>");
sb.appendHtmlConstant(" <span>Feeling:</span>");
sb.appendHtmlConstant(" <select id=\"" +
SafeHtmlUtils.fromTrustedString(ELEMENT_FEELING_ID) + "\">");
sb.appendHtmlConstant(" </select>");
sb.appendHtmlConstant(" </td>");
sb.appendHtmlConstant(" </tr>");
sb.appendHtmlConstant(" <tr>");
sb.appendHtmlConstant(" <td id=\"tbc\" class=\"nbItemRow\">");
sb.appendHtmlConstant(" <span>Expected Complete:</span>");
sb.appendHtmlConstant(" <input type=\"text\" id=\"" +
SafeHtmlUtils.fromTrustedString(ELEMENT_TOWN_ID) + "\"></input>");
sb.appendHtmlConstant(" <input type=\"button\" value=\"Update\"
class=\"nbButton\"id=\"" +
SafeHtmlUtils.fromTrustedString(ELEMENT_BUTTON_UPDATE_ID) + "\"></
input>");
sb.appendHtmlConstant(" </td>");
sb.appendHtmlConstant(" </tr>");
sb.appendHtmlConstant(" </table> ");
sb.appendHtmlConstant(" </td>");

// end
sb.appendHtmlConstant(" </tr>");
sb.appendHtmlConstant(" </table>");
sb.appendHtmlConstant("</div>");

}

@Override
public void onBrowserEvent(Element parent, NodeDTO value, Object key,
NativeEvent event, ValueUpdater<NodeDTO> valueUpdater) {

super.onBrowserEvent(parent, value, key, event, valueUpdater);
String type = event.getType();
if ("change".equals(type)) {

printElementTree(parent, 1);

// InputElement txtPctProgress =
// SelectElement select = parent.getFirstChild().cast();
// String newValue = options.get(select.getSelectedIndex());
// setViewData(key, newValue);
// finishEditing(parent, newValue, key, valueUpdater);
// if (valueUpdater != null) {
// valueUpdater.update(newValue);
// }
}

}

@Override
protected void finishEditing(Element parent, NodeDTO value, Object
key, ValueUpdater<NodeDTO> valueUpdater) {
//super.finishEditing(parent, value, key, valueUpdater);
String newValue = getInputElement(parent).getValue();

// newValue is always null
System.out.println("NEW VALUE = " + newValue);


}

private static void printElementTree(Node n, int level) {
NodeList<Node> childNodes = n.getChildNodes();

String indicator = "";

for (int h=0; h<level; h++) {
indicator = indicator + "> ";
}

level = level + 1;

for (int i=0; i<childNodes.getLength(); i++) {
Node nDOM = childNodes.getItem(i);

String type = "";

switch (nDOM.getNodeType()) {
case Node.ELEMENT_NODE:
type = "element node";
Element e = Element.as(nDOM);
System.out.println(indicator+ "Child DOM element " +
nDOM.getNodeName() + " value= " + nDOM.getNodeValue() + " type= " +
type + " id= " + e.getId());
case Node.DOCUMENT_NODE:
type = "document node";
System.out.println(indicator+ "Child DOM element " +
nDOM.getNodeName() + " value= " + nDOM.getNodeValue() + " type= " +
type);
case Node.TEXT_NODE:
type = "text node";
System.out.println(indicator+ "Child DOM element " +
nDOM.getNodeName() + " value= " + nDOM.getNodeValue() + " type= " +
type);
}


printElementTree(nDOM, level);
}
}


@Override
protected InputElement getInputElement(Element parent) {
return super.getInputElement(parent).<InputElement> cast();
}

/**
* The {@code ViewData} for this cell.
*/
public static class ViewData {
/**
* The last value that was updated.
*/
private String lastValue;

/**
* The current value.
*/
private String curValue;

/**
* Construct a ViewData instance containing a given value.
*/
public ViewData(String value) {
this.lastValue = value;
this.curValue = value;
}

/**
* Return true if the last and current values of this ViewData
object
* are equal to those of the other object.
*/
@Override
public boolean equals(Object other) {
if (!(other instanceof ViewData)) {
return false;
}
ViewData vd = (ViewData) other;
return equalsOrNull(lastValue, vd.lastValue)
&& equalsOrNull(curValue, vd.curValue);
}

/**
* Return the current value of the input element.
*/
public String getCurrentValue() {
return curValue;
}

/**
* Return the last value sent to the {@link ValueUpdater}.
*/
public String getLastValue() {
return lastValue;
}

/**
* Return a hash code based on the last and current values.
*/
@Override
public int hashCode() {
return (lastValue + "_*!@HASH_SEPARATOR@!*_" +
curValue).hashCode();
}

/**
* Set the current value.
*
* @param curValue the current value
*/
protected void setCurrentValue(String curValue) {
this.curValue = curValue;
}

/**
* Set the last value.
*
* @param lastValue the last value
*/
protected void setLastValue(String lastValue) {
this.lastValue = lastValue;
}

private boolean equalsOrNull(Object a, Object b) {
return (a != null) ? a.equals(b) : ((b == null) ? true : false);
}
}

}

John LaBanca

unread,
Dec 3, 2010, 9:34:24 AM12/3/10
to google-we...@googlegroups.com
AbstractInputCell is intended to be wrap a single input element, not an entire form.  Specifically, you need to override getInputElement(parent) to dig into the DOM and get the input element that you are wrapping.  By default, getInputElement(parent) gets the first child of the parent, assuming that the cell renders a single input element and nothing else.  Still, even if you override getInputElement, you'll only be able to return one value.

What you really need to do is create a new AbstractEditableCell.  In onBrowserEvent, catch the change event and dig down to all of the input elements in the form, updating the DTO as needed.

Thanks,
John LaBanca
jlab...@google.com



--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.


sevendays

unread,
Dec 4, 2010, 4:09:45 AM12/4/10
to Google Web Toolkit
Thanks John, however this did not resolve my problem. I did what you
suggested but I'm still having trouble seeing the 'value' set on the
<input> elements. I did the following:

1) Change to extending AbstractEditableCell.
2) Changed to using a Template combined with a SafeHtml renderer for
the <input> tags.
3) Pick up the "change" event in onBrowserEvent (see code snippet
below)
4) Inspect DOM tree to get the appropriate InputElement, then call
getNodeValue() (see code snippet below)

The problem is that getNodeValue() is null, even when the Element is
definitely the correct one and after I have entered a value in the
<input> field. It seems that when I enter a value in the form field,
it doesn't make it onto the DOM tree, and therefore isn't seen by GWT.

Any suggestions?


----------


private static InputElement findElementTreeRecursive(Node n, String
id) {

if (n.getNodeType() == Node.ELEMENT_NODE) {
Element e = Element.as(n);

System.out.println(" let's compare element " + e.getId() + " with "
+ id);

if (e.getId().equals(id)) {
System.out.println("findElementTreeRecursive found element " +
e.getNodeName() + ", value= " + e.getNodeValue() + ", id= " +
e.getId());
return (InputElement) e;
}
}

NodeList<Node> childNodes = n.getChildNodes();

for (int i=0; i<childNodes.getLength(); i++) {
Node nDOM = childNodes.getItem(i);

findElementTreeRecursive(nDOM, id);
}

System.out.println("findElementTreeRecursive NOT FOUND ELEMENT :( ");

return null;
}


-----------------



@Override
public void onBrowserEvent(Element parent, NodeDTO value, Object key,
NativeEvent event, ValueUpdater valueUpdater) {
// Check that the value is not null.
if (value == null) {
return;
}

// Call the super handler, which handlers the enter key.
super.onBrowserEvent(parent, value, key, event, valueUpdater);

if ("change".equals(event.getType())) {
Element target = event.getEventTarget().cast();
// findElementTreeRecursive() is called within getInputElement()
InputElement inputPctComplete = getInputElement(parent,
ELEMENT_AGE_ID);
}
}


On Dec 4, 12:34 am, John LaBanca <jlaba...@google.com> wrote:
> AbstractInputCell is intended to be wrap a single input element, not an
> entire form.  Specifically, you need to override getInputElement(parent) to
> dig into the DOM and get the input element that you are wrapping.  By
> default, getInputElement(parent) gets the first child of the parent,
> assuming that the cell renders a single input element and nothing else.
>  Still, even if you override getInputElement, you'll only be able to return
> one value.
>
> What you really need to do is create a new AbstractEditableCell.  In
> onBrowserEvent, catch the change event and dig down to all of the input
> elements in the form, updating the DTO as needed.
>
> Thanks,
> John LaBanca
> jlaba...@google.com
> ...
>
> read more »

John LaBanca

unread,
Dec 6, 2010, 1:45:21 PM12/6/10
to google-we...@googlegroups.com
Try using InputElement#getValue() instead of Node#getNodeValue().  I'm not exactly sure what nodeValue is, but I don't think its the same thing as the input value.

Element e = Element.as(n);
InputElement input = e.cast();
String value = input.getValue();

Thanks,
John LaBanca
jlab...@google.com



--

sevendays

unread,
Dec 7, 2010, 7:38:06 AM12/7/10
to Google Web Toolkit
Sorted. Thanks John!

On Dec 7, 4:45 am, John LaBanca <jlaba...@google.com> wrote:
> Try using InputElement#getValue() instead of Node#getNodeValue().  I'm not
> exactly sure what nodeValue is, but I don't think its the same thing as the
> input value.
>
> Element e = Element.as(n);
> InputElement input = e.cast();
> String value = input.getValue();
>
> Thanks,
> John LaBanca
> jlaba...@google.com
> ...
>
> read more »
Reply all
Reply to author
Forward
0 new messages