Making a standalone proto to show a bug, I think I have hit another one...
I get an error message:
AssertionError: The given model is already in the TreeStore, and should not be assigned a new node
in TreeStore.wrap()
The message isn't very explicit as I think it only shows I tried to add data to a store that is already there. Although maybe it is accurate after all.
I have a tree in a BorderLayoutContainer, in the West wing...
In the asWidget() method of the class instantiating the tree, I do as it is done in most Sencha demos: I call the createAndBindUi, I initialize the tree, including initializing the RPC that will fill it, and I return the widget.
After investigation, I see the West init (and the others) use a two-fold scheme:
Code:
@Override
public void setWestWidget(IsWidget child) {
if (west != null) {
remove(west);
}
if (child != null) {
west = child.asWidget();
insert(west, 0);
}
}
@UiChild(limit = 1, tagname = "west")
public void setWestWidget(IsWidget child, BorderLayoutData layoutData) {
if (child != null) {
child.asWidget().setLayoutData(layoutData);
}
setWestWidget(child);
}
Do you see the problem? child.asWidget() is called twice!
So there is two attempts to fetch the data.
Now, I don't write this message in the Bug section, because perhaps I violated a "GWT best practice", I don't know.
The workaround is simple: just create the widget in the constructor of the class, and make asWidget() only return the widget class field.
But it is far from obvious from the (necessarily simplified) examples for a GWT newbie like me. Perhaps you should add a stern warning somewhere, prominently, to warn against such practice (ie. doing too much work in asWidget()).
Or perhaps you can avoid such double call by changing the code to something like:
Code:
private void setWestWidget(Widget w) {
if (west != null) {
remove(west);
}
if (w != null) {
west = w;
insert(west, 0);
}
}
@Override
public void setWestWidget(IsWidget child) {
if (child != null) {
setWestWidget(child.asWidget());
} else {
setWestWidget(null);
}
}
@UiChild(limit = 1, tagname = "west")
public void setWestWidget(IsWidget child, BorderLayoutData layoutData) {
Widget w = null;
if (child != null) {
w = child.asWidget();
w.setLayoutData(layoutData);
}
setWestWidget(w);
}
This breaks the cross-call between the public methods, avoiding this issue.
It is more friendly for the kind of error / sloppy coding I made.
At least, I hope this message can be useful for somebody having hit the same error... 