We are developing a new application in Wicket and have run into a small problem.
What we do:
1) create a new SortableDataProvider
2) create a new DefaultDataTablePagingInBottom
3) create a new WebMarkupContainer
4) add the DefaultDataTablePagingInBottom to the WebMarkupContainer
5) create a new AjaxCheckBox
6) in the onUpdate of the AjaxCheckBox, add the WebMarkupContainer to the AjaxRequestTarget
7) set the SortableDataProvider to a new SortableDataProvider (with the updated query)
8) DefaultDataTablePagingInBottom.replaceWith(new DefaultDataTablePagingInBottom - with the new provider).
What happends:
1) Click the checkbox -> nothing happends.
2) Click it again -> crash: "Last cause: This method can only be called on a component that has already been added to its parent.
WicketMessage: Method onRequest of interface org.apache.wicket.behavior.IBehaviorListener targeted at org.apache.wicket.ajax.markup.html.form.AjaxCheckBox$1@1a2fefd on component [ [Component id = checkBox]] threw an exception"
3) Click back in the browser -> the list i filtered with the new provider.
Any ideas?
---EDIT--- Here's some code.
1) In the constructor of the WebPage:
model = new Model(projectPlannerService);
provider = new SortableProjectDataProvider(model, (WebSession) getSession(), isChecked);
table = new DefaultDataTablePagingInBottom("table", columns, provider, 50);
listContainer = new WebMarkupContainer("wmc");
listContainer.add(table);
add(listContainer.setOutputMarkupId(true));
/*
* checkbox för filtrering
*/
AjaxCheckBox checkBox = new AjaxCheckBox("checkBox", new Model()) {
@Override
protected void onUpdate(AjaxRequestTarget target) {
target.add(listContainer, "wmc");
isChecked = !isChecked;
provider = new SortableProjectDataProvider(model, (WebSession) getSession(), isChecked);
updateTable();
}
};
add(checkBox);
2) In updateTable():
table.replaceWith(new DefaultDataTablePagingInBottom("table", columns, provider, 50));
3) The SortableProjectDataProvider:
// Constructor
public SortableProjectDataProvider(IModel<?> model, WebSession webSession, boolean isChecked) {
this.model = model;
this.projectPlannerService = (ProjectPlannerService) model.getObject();
this.webSession = webSession;
setSort("customer", SortOrder.ASCENDING);
System.out.println("ischecked:" + isChecked);
if(!isChecked)
list = ((ProjectPlannerService) model.getObject()).findAllProjects();
else
list = ((ProjectPlannerService) model.getObject()).findAllActiveProjects();
System.out.println("size: " + list.size());
comparator = new ProjectComparator();
}
public Iterator<Project> iterator(int first, int count) {
Collections.sort(list, comparator);
if (first > list.size()) {
first = 0;
}
if (first + count > list.size()) {
return list.subList(first, list.size()).iterator();
} else {
return list.subList(first, first + count).iterator();
}
}
public IModel<Project> model(Project object) {
return new DetachableProjectModel((Project) object);
}
public int size() {
return list.size();
}
private class DetachableProjectModel extends LoadableDetachableModel {
private Long id;
@SpringBean
ProjectPlannerService projectPlannerService;
public DetachableProjectModel(Long id) {
Injector.get().inject(this);
if (id == null) {
throw new IllegalArgumentException();
}
this.id = id;
}
public DetachableProjectModel(Project project) {
this(project.getPk());
Injector.get().inject(this);
}
public int hashCode() {
return id.hashCode();
}
public boolean equals(final Object obj) {
if (obj == this) {
return true;
} else if (obj == null) {
return false;
} else if (obj instanceof DetachableProjectModel) {
DetachableProjectModel other = (DetachableProjectModel) obj;
return other.id == this.id;
}
return false;
}
protected Object load() {
return ((ProjectPlannerService) model.getObject()).findProjectById(id);
}
}
}
wicket:extend
-input wicket:id="checkBox" type="checkbox"- Show active -/input-
-div wicket:id="wmc"-
-table wicket:id="table"--/table-
-/div-
-/wicket:extend-
Thanks in advance!
/Andreas
Try this:
Wrong: target.add(listContainer, "wmc");
Right: target.add(listContainer);
Wrong; table.replaceWith(new DefaultDataTablePagingInBottom("table", columns, provider, 50));
Right: DefaultDataTablePagingInBottom tmp = new DefaultDataTablePagingInBottom("table", columns, provider, 50);
table.replaceWith(tmp);
table = tmp;
(You replace the DefaultDataTablePagingInBottom but not your reference.)
//olle
By replacing the instance of your SortableProjectDataProvider
with a new one you are making your life difficult. Instead of using the boolean isChecked
in the constructor you could use an IModel<Boolean>
. Assign the same instance of that model to your data provider and the check-box and you are done. No need to replace anything in onUpdate
, add your listContainer
to the AjaxRequestTarget
and everything should just work...
e.g.
...
private IModel<Boolean> isCheckedModel = new Model<Boolean>(Boolean.FALSE);
...
provider = new SortableProjectDataProvider(model, (WebSession) getSession(), isCheckedModel);
...
AjaxCheckBox checkBox = new AjaxCheckBox("checkBox", isCheckedModel) {
@Override
protected void onUpdate(AjaxRequestTarget target) {
target.add(listContainer);
}
};
...
It is almost never a good idea to replace such things with new ones in Wicket. Encapsulate what changes in a model and change / replace the model's object. Every object that has a reference to that model can see the updated value or change it as needed.
Hope this helps.