checkbox not getting unchecked in wicket - wicket

I have a checkgroup and on selecting a checkbox in the group I want to get the number of selected/checked check boxes.
By the below code, I am able to get the selected number of checkboxes but on unchecking or removing the selection, i see that its still selected.
Example : I have selected 2 now I get 2 string selected.
Now I unselect one checkbox, even now i get 2 strings selected. While I expect one string to be checked.
The code is given below:
final CheckGroup myGroup = new CheckGroup("group", new ArrayList()) {
#Override
protected Collection<String> convertValue(String[] values) throws ConversionException {
Collection<String> myCollection = super.convertValue(values);
checkedString.addAll(myCollection);
HashMap<Integer, String> myTempList = new HashMap<Integer, String>();
for (String myString : checkedString) {
myTempList.put(myString.getSystemId(), myString);
}
checkedString.clear();
for (Entry<Integer, String> myEntry : myTempList.entrySet()) {
checkedString.add(myEntry.getValue());
}
return checkedString;
}
#Override
protected void onSelectionChanged(Collection newSelection) {
newSelection = checkedString;
}
#Override
protected boolean wantOnSelectionChangedNotifications() {
return true;
}
};
add(myForm);
myForm.add(myGroup);

Add a behavior to your component
sampleChckbox.add(new AjaxFormComponentUpdatingBehavior("onclick"){
#Override
protected void onUpdate(AjaxRequestTarget target) {
//perform your operation here
}
This method will fire an Ajax request on "onClick" event; which will update your backend logic at runtime
edit :
To be very specific to CheckGroup class use the AjaxFormChoiceComponentUpdatingBehavior
AjaxFormChoiceComponentUpdatingBehavior is the behavior to use with CheckGroups and RadioGroups. If you used an AjaxFormComponentUpdatingBehavior with the onchange event, you'd run into this bug with IE
. AjaxFormChoiceComponentUpdatingBehavior handles this properly, adding onclick event handlers to each of the Checks in the CheckGroup.
As a side note, what Igor stated in that mail, is that CheckBox can be replaced with AjaxCheckBox, not Check. AjaxCheckBox is nothing more than a convenience subclass of CheckBox with an AjaxFormComponentUpdatingBehavior("onclick"), as the sources show.

Related

What is the right usage for the SingleSelectionModel?

we would like to link from a CellTable to a property editor page. We use the SingleSelectionModel to get notified, when a user clicks on an item.
It is initialized like this:
private final SingleSelectionModel<Device> selectionModel = new SingleSelectionModel<Device>();
We then assign the selection change handler:
selectionModel.addSelectionChangeHandler(this);
Our selection change handler looks like this:
#Override
public void onSelectionChange(SelectionChangeEvent event) {
Log.debug("DevicesPresenter: SelectionChangeEvent caught.");
Device selectedDevice = selectionModel.getSelectedObject();
if (selectedDevice != null) {
selectionModel.clear();
if (selectionModel.getSelectedObject() != null){
Log.debug("DevicesPresenter: selected item is " + selectionModel.getSelectedObject());
}
else{
Log.debug("DevicesPresenter: selected item is null");
}
deviceEditorDialog.setCurrentDevice(selectedDevice.getUuid());
// get the container data for this device
clientModelProvider.fetchContainersForDevice(selectedDevice.getUuid());
PlaceRequest request = new PlaceRequest.Builder()
.nameToken(NameTokens.deviceInfo)
.with("uuid", selectedDevice.getUuid())
.build();
Log.debug("Navigating to " + request.toString());
placeManager.revealPlace(request);
}
}
Now there are two issues: There always seem to be two SelectionChangeEvents at once and i really cannot see why. The other thing is: How is the right way do handle selection of items and the related clearing of the selection model? Do we do that the right way?
Thanks!
If you only want to get notified of "clicks" without keeping the "clicked" item selected, use a NoSelectionModel instead; no need to clear the selection model as soon as something is selected.
As for your other issue with being called twice, double-check that you haven't added your selection handler twice (if you can unit-test your DevicesPresenter, introspect the handlers inside the selection model for example)
In your line selectionModel.addSelectionChangeHandler(this); what does this refer?
Here my code how I use SingleSelectionModel
public class MyClass{
private final SingleSelectionModel<CountryDto> selectionModel = new SingleSelectionModel<CountryDto>();
...
public MyClass(){
cellTable.setSelectionModel(selectionModel);
selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
#Override
public void onSelectionChange(SelectionChangeEvent event) {
CountryDto selected = selectionModel
.getSelectedObject();
if (selected != null) {
Window.alert("Selected country "+selected.getTitle());
}
}
});
}
}

How can I observe the changed state of model items in an ObservableList?

I have an ObservableList of model items. The model item is enabled for property binding (the setter fires a property changed event). The list is the content provider to a TableViewer which allows cell editing. I also intend to add a way of adding new rows (model items) via the TableViewer so the number of items in the list may vary with time.
So far, so good.
As this is all within an eclipse editor, I would like to know when the model gets changed. I just need one changed event from any changed model item in order to set the editor 'dirty'. I guess I could attach some kind of listener to each individual list item object but I wonder if there is a clever way to do it.
I think that I might have a solution. The following class is an inline Text editor. Changes to the model bean (all instances) are picked up using the listener added in doCreateElementObservable. My eclipse editor just needs to add its' own change listener to be kept informed.
public class InlineEditingSupport extends ObservableValueEditingSupport
{
private CellEditor cellEditor;
private String property;
private DataBindingContext dbc;
IChangeListener changeListener = new IChangeListener()
{
#Override
public void handleChange(ChangeEvent event)
{
for (ITableEditorChangeListener listener : listenersChange)
{
listener.changed();
}
}
};
public InlineEditingSupport(ColumnViewer viewer, DataBindingContext dbc, String property)
{
super(viewer, dbc);
cellEditor = new TextCellEditor((Composite) viewer.getControl());
this.property = property;
this.dbc = dbc;
}
protected CellEditor getCellEditor(Object element)
{
return cellEditor;
}
#Override
protected IObservableValue doCreateCellEditorObservable(CellEditor cellEditor)
{
return SWTObservables.observeText(cellEditor.getControl(), SWT.Modify);
}
#Override
protected IObservableValue doCreateElementObservable(Object element, ViewerCell cell)
{
IObservableValue value = BeansObservables.observeValue(element, property);
value.addChangeListener(changeListener); // ADD THIS LINE TO GET CHANGE EVENTS
return value;
}
private List<ITableEditorChangeListener> listenersChange = new ArrayList<ITableEditorChangeListener>();
public void addChangeListener(ITableEditorChangeListener listener)
{
listenersChange.remove(listener);
listenersChange.add(listener);
}
public void removeChangeListener(ITableEditorChangeListener listener)
{
listenersChange.remove(listener);
}
}

GWT Header CheckBox requires two clicks to fire setValue, after changing its value programatically

I have a GWT DataGrid, and a CheckBox in the Header to select/deselect all rows in the grid.
The code for the CheckBox Header is as follows:
private class CheckboxHeader extends Header<Boolean> implements HasValue<Boolean> {
private boolean checked;
private HandlerManager handlerManager;
/**
* An html string representation of a checked input box.
*/
private final SafeHtml INPUT_CHECKED = SafeHtmlUtils.fromSafeConstant("<input type=\"checkbox\" tabindex=\"-1\" checked/>");
/**
* An html string representation of an unchecked input box.
*/
private final SafeHtml INPUT_UNCHECKED = SafeHtmlUtils.fromSafeConstant("<input type=\"checkbox\" tabindex=\"-1\"/>");
#Override
public void render(Context context, SafeHtmlBuilder sb) {
if (Boolean.TRUE.equals(this.getValue())) {
sb.append(INPUT_CHECKED);
} else {
sb.append(INPUT_UNCHECKED);
}
};
public CheckboxHeader() {
super(new CheckboxCell(true, false));
checked = true;
}
// This method is invoked to pass the value to the CheckboxCell's render method
#Override
public Boolean getValue() {
return checked;
}
#Override
public void onBrowserEvent(Context context, Element elem, NativeEvent nativeEvent) {
int eventType = Event.as(nativeEvent).getTypeInt();
if (eventType == Event.ONCHANGE) {
nativeEvent.preventDefault();
// use value setter to easily fire change event to handlers
setValue(!checked, true);
}
}
#Override
public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Boolean> handler) {
return ensureHandlerManager().addHandler(ValueChangeEvent.getType(), handler);
}
#Override
public void fireEvent(GwtEvent<?> event) {
ensureHandlerManager().fireEvent(event);
}
#Override
public void setValue(Boolean value) {
setValue(value, true);
}
#Override
public void setValue(Boolean value, boolean fireEvents) {
checked = value;
if (fireEvents) {
ValueChangeEvent.fire(this, value);
}
}
private HandlerManager ensureHandlerManager() {
if (handlerManager == null) {
handlerManager = new HandlerManager(this);
}
return handlerManager;
}
}
So, I add the Header to the grid, and I add a ValueChangeHandler to it to do the actual selecting/deselecting of individual CheckBox cells in every row of the grid. This all works.
Every CheckBoxCell has a Field Updater, and on every update it loops through every item in the grid to see if they are all checked, and update the header check box. If at least one is unchecked, the header checkbox will be unchecked. I call setValue() on the header check box, and after that I call redrawHeaders() on the entire grid. This also works.
What doesn't work is - after changing the "state" of the header check box programatically, it takes two clicks for it to fire it's internal setValue again, and therefore trigger my handler. And what's even funnier - the first click does change the state of the check box, but it just doesn't fire the event.
Any help would be appreciated.
How are you constructing the CheckboxCells themselves? I ran into a similar issue with a column of checkboxes "eating" clicks, and the solution was to call CheckboxCell cell = new CheckboxCell(true,true) and then pass that cell into the constructor of the column.

Wicket - changing panels through a dropdown

I have a dropdown component added on a page. the purpose of this dropdown is to change the type of input form that is rendered. for example, different forms have different required fields, editable fields, etc.
public final class Test extends WebPage
{
CustomPanel currentPanel = new MeRequest("repeater",FormType.MIN);
public Test(PageParameters parameters)
{
add(currentPanel);
DropDownChoice ddc = new DropDownChoice("panel", new PropertyModel(this, "selected"), panels, choiceRenderer);
ddc.add(new AjaxFormComponentUpdatingBehavior("onchange") {
protected void onUpdate(AjaxRequestTarget target) {
System.out.println("changed");
currentPanel = new MeRequest("repeater",FormType.PRO);
target.add(currentPanel);
}
});
add(ddc);
}
i've tried various options with limited results. the only real success has been updating the model, but what i really want to do is change how the components behave.
any thoughts on what i'm missing?
1) If you want to replace one panel with another you may just do the following.
First of all, you should output the markup id of the original panel:
currentPanel.setOutputMarkupId(true);
And then in the ajax event handler write something like that:
protected void onUpdate(AjaxRequestTarget target) {
CustomPanel newPanel = new MeRequest("repeater", FormType.PRO);
currentPanel.replaceWith(newPanel);
currentPanel = newPanel;
currentPanel.setOutputMarkupId(true);
target.addComponent(currentPanel);
}
In this case with every change of dropdown choice you add new panel to the page and you remove old panel from the page.
2) But I would proposed a slightly different approach to your problem. You should move the construction logic of your panel to the onBeforeRender() method:
public class MeRequest extends Panel {
private FormType formType;
public MeRequest(String id, FormType formType) {
super(id);
this.formType = formType;
// don't forget to output the markup id of the panel
setOutputMarkupId(true);
// constructor without construction logic
}
protected void onBeforeRender() {
// create form and form components based on value of form type
switch (formType) {
case MIN:
// ...
break;
case PRO:
// ...
break;
}
// add form and form components to panel
addOrReplace(form);
form.add(field1);
form.add(field2);
// ...
super.onBeforeRender();
}
public void setFormType(FormType formType) {
this.formType = formType;
}
}
Then you'll be able to only change type of the panel in the ajax event:
protected void onUpdate(AjaxRequestTarget target) {
currentPanel.setFormType(FormType.PRO);
target.addComponent(currentPanel);
}
Thus we rebuilt the original panel without recreating it.

wicket issue unable to move items from one listmultiplechoice another

I have a Wicket Panel. It has two text fields adjacent to each other and two ListMultipleChoice controls adjacent to each other and two buttons "add and remove" in between two these ListMultipleChoice's.
I was unable to move the items from one list box to another unless I entered some values in text fields, which were prior to the list boxes.
If values were entered in text fields, I was able to move the items.
Please find the code below.
TextField<BigDecimal> textfield1 = new TextField<BigDecimal>("value1")
{
private static final long serialVersionUID = 8199976201679629866L;
#Override
public IConverter getConverter(Class<?> type) {
return new FixedDecimalPlacesConverter();
}
};
textfield1.setType(BigDecimal.class);
textfield1.setLabel(new Model<String>("Value1"));
textfield1.setRequired(true)
.add(PositiveNumberValidator.getInstance())
.add(new FixedDecimalPlacesValidator(2));
add(new FeedBackBorder("Border1").add(textfield1));
TextField <BigDecimal> textfield2 = new TextField<BigDecimal>("value2")
{
private static final long serialVersionUID = 8199976201679629866L;
#Override
public IConverter getConverter(Class<?> type) {
return new FixedDecimalPlacesConverter();
}
};
textfield2.setType(BigDecimal.class);
textfield2.setOutputMarkupId(true);
textfield2.setLabel(new Model<String>("Value2"));
textfield2.setRequired(true)
.add(PositiveNumberValidator.getInstance())
.add(new FixedDecimalPlacesValidator(2));
add (new FeedBackBorder("Border2").add(textfield2));
ChoiceRenderer<UserBean> choiceRenderer = new ChoiceRenderer<UserBean>("userName", "userID.ID");
availableUsers= new ListMultipleChoice<UserBean>( "availableUsersBean", availableUsersList, choiceRenderer );
availableUsers.setOutputMarkupId(true);
availableUsers.setLabel(new Model<String>("Available Users"));
add(new FeedBackBorder("availableUsersBorder").add(availableUsers));
selectedUsers = new ListMultipleChoice<UserBean>( "selectedUsersBean", selectedUsersList, choiceRenderer );
selectedUsers.setOutputMarkupId(true);
selectedUsers.setLabel(new Model<String>("Selected Users"));
add(new FeedBackBorder("selectedUsers Border").add(selectedUsers ));
add = new AjaxButton("add") {
#Override
protected void onSubmit(AjaxRequestTarget target, Form form) {
update(target, availableUsers.getModelValue(),availableUsers, selectedUsers);
}
};
add(new FeedBackBorder("addBorder").add(add));
remove = new AjaxButton("remove") {
#Override
protected void onSubmit(AjaxRequestTarget target, Form form) {
update(target, selectedUsers.getModelValue(), selectedUsers , availableUsers);
}
};
add(new FeedBackBorder("removeBorder").add(remove));
What could be the issue?
add.setDefaultFormProcessing(false);
remove.setDefaultFormProcessing(false);
I am using org.apache.wicket.markup.html.form.Button which allows you to turn off full form submit with button click with the setDefaultFormProcessing(boolean). This should allow you to process actions without submitting your complete form, therefore not validating required textfields.
At a first glance: Your TextFields are required. Submitting the Form via AjaxButtons wouldn't trigger the onSubmit method for an invalid form but the onError method.
Possible Solutions (in no particular order):
Moving the Lists to a nested form
Moving the contents of the onSubmit to a separate method and call it from onError too
Move the item moving logic to a pure JavaScript based Behaviour or Decorator that doesn't trigger a form submit.