Start interval after button click wicket - wicket

I'm trying to start an interval after button click.
button = form.add(new AjaxButton("button") {
#Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
AjaxSelfUpdatingTimerBehavior ajaxSelfUpdatingTimerBehavior = new AjaxSelfUpdatingTimerBehavior(Duration.seconds(5)) {
private static final long serialVersionUID = 1L;
#Override
protected void onPostProcessTarget(AjaxRequestTarget target) {
logger.debug("onPostProcessTarget");
}
};
this.add(ajaxSelfUpdatingTimerBehavior);
}
});
});
The previous AjaxSelfUpdatingTimerBehavior does not start after button click. How can I make it start?
The wierd thing is if I add a new one like this after the previous block
button.add(new AjaxSelfUpdatingTimerBehavior(Duration.seconds(5)) {
private static final long serialVersionUID = 1L;
#Override
protected void onPostProcessTarget(AjaxRequestTarget target) {
logger.debug("onPostProcessTarget2");
}
});
both of them start. But the last one also updates the dom which I don't want.
So all in all how can I start an interval after button click? (similarly to first code snippet)

Unlike regular form submission, ajax form submission (via an ajax button like you do here) is not going to re-render anything that you don't explicitly state you want re-rendered by performing target.add(...) on it.
What this means is that any changes you make to the component hierarchy or components themselves (like adding a new behavior) are going to stay in the back-end until you either update the individual components, or re-render the whole page.
In order to propogate any state changes in an ajax request call target.add(this) in your form submission. This will make wicket update the component and hence add the new behaviors of it to the front-end.
So given your example the code should look like the following:
button = form.add(new AjaxButton("button") {
#Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
AjaxSelfUpdatingTimerBehavior ajaxSelfUpdatingTimerBehavior = new AjaxSelfUpdatingTimerBehavior(Duration.seconds(5)) {
private static final long serialVersionUID = 1L;
#Override
protected void onPostProcessTarget(AjaxRequestTarget target) {
logger.debug("onPostProcessTarget");
}
};
this.add(ajaxSelfUpdatingTimerBehavior);
target.add(this);
}
});
});

Related

Can't submit on dropdown lazy loading

My form has 1 dropdown use AjaxLazyLoadPanel and 1 ajax button submit.
I click button submit that works only when the dropdown is finished loading.
Index.java
form.add(new AjaxLazyLoadPanel("lazy") {
private static final long serialVersionUID = 1L;
#Override
public Component getLazyLoadComponent(String markupId) {
Fragment fr = new Fragment(markupId, "lazyContentFragment", Index.this);
fr.add(dropdown());
return fr;
}
});
form.setOutputMarkupId(true);
form.add(new AjaxButton("search") {
#Override
protected void onError(AjaxRequestTarget target) {
target.add(feedback);
}
#Override
protected void onSubmit(AjaxRequestTarget target) {
//do something...
}
});
Index.html
<form wicket:id="form">
<input wicket:id="textbox"/>
<div wicket:id="lazy"></div>
<button wicket:id="search"></button>
</form>
<wicket:fragment wicket:id="lazyContentFragment">
<select wicket:id="dropdown"></select>
</wicket:fragment>
Is there any way to submit the form without waiting for the dropdown finish loading.
By default wicket-ajax.js serializes the Ajax calls to the server. This is being done so that the second Ajax call is not called if its HTML element is being removed/painted by the first Ajax call.
In addition only one thread can manipulate a Page instance at a time at the server side!
To be able to make two Ajax calls at the same time you need to use different AjaxChannels for them. For example:
... = new AjaxButton("someId") {
#Override protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
{
attributes.setChannel(new AjaxChannel("customName"));
}
}
This way both Ajax requests will be fired to the server, but the AjaxButton's one will be processed only after the AjaxLazyLoadingPanel's one releases the lock on the page instance at the server side. There is no way to execute two threads on the same page instance (i.e. having the same pageId).
If you're dropdown's choices are taking so long to load, you might want to make your AjaxLazyLoadPanel asynchronous by overriding #isContentReady():
private String token;
private List<T> choices;
protected boolean isContentReady()
{
if (token == null) {
token = startLoadingChoices();
} else {
choices = checkChoicesLoaded(token);
}
return choices != null;
}
Since Wicket manages and serializes all pages, your page must not be held as a reference in a thread or a listener in central registry. Keep a token instead and ask for the loading result; #isContentReady() will be polled repeatedly until it returns true.

Same AjaxEventBehavior for multiple components

I add an image and a text component to a WebMarkupContainer as described here:
filter.add(newFilterLabel("textSub", customerText, filtervalue));
filter.add(newFilterImage("imgSub", filtervalue));
For each component, there is an AjaxEventBehavior doing different things. I would like to change it in a way that both do the same thing independent from which component has been clicked on.
private Component newFilterLabel(String id, IModel<String> customText,
final SourceFilterValue currentValue) {
final BBLabel label = new BBLabel(id, customText);
label.add(new AjaxEventBehavior("onclick") {
private static final long serialVersionUID = 1L;
#Override
protected void onEvent(AjaxRequestTarget target) {
doSomething(currentValue,filteredsources, target);
}
});
return label;
}
private Image newFilterImage(String id, final SourceFilterValue filterValue) {
final Image img = new Image(id, resources.getImage(EXPAND_ICON));
img.add(new AjaxEventBehavior("onclick") {
private static final long serialVersionUID = 1L;
#Override
protected void onEvent(AjaxRequestTarget target) {
doSomething(img);
}
});
return img;
}
Do you have any suggestions how to change it or any workaround? I use Wicket 1.5.8.
An AjaxBehavior can be bound to a single element only. Either add it to a parent in the hierarchy, or just let both behaviors call the same method:
#Override
protected void onEvent(AjaxRequestTarget target) {
doSomething(filterValue); //filterValue has to be final to be able to access it from the inner class
}

Attempt to set model object on null model of component: form:checkgroup

I'm trying to create a list of HITs (objects), where each has a checkbox next to it, so that I can select them and delete them all at once. I've made a form with a checkbox for each row in the table:
final HashSet<HIT> selectedValues = new HashSet<HIT>();
final CheckGroup checkgroup = new CheckGroup("checkgroup");
final Form form = new Form("form"){
#Override
public void onSubmit() {
super.onSubmit();
}
};
checkgroup.add(new CheckGroupSelector("checkboxSelectAll"));
UserHitDataProvider userHitDataProvider = new UserHitDataProvider(selectedIsReal, keyId, secretId);
final DataView<HIT> dataView = new DataView<HIT>("pageable", userHitDataProvider) {
private static final long serialVersionUID = 1L;
#Override
protected void populateItem(final Item<HIT> item) {
HIT hit = item.getModelObject();
item.add(new CheckBox("checkbox", new SelectItemUsingCheckboxModel(hit,selectedValues)));
item.add(new Label("hitName", String.valueOf(hit.getTitle())));
item.add(new Label("hitId", String.valueOf(hit.getHITId())));
}
};
//add checkgroup to form, form to page, etc.
I've also added a new class to take care of the selection/deletion:
public class SelectItemUsingCheckboxModel extends AbstractCheckBoxModel {
private HIT hit;
private Set selection;
public SelectItemUsingCheckboxModel(HIT h, Set selection) {
this.hit = h;
this.selection = selection;
}
#Override
public boolean isSelected() {
return selection.contains(hit);
}
#Override
public void select() {
selection.add(hit);
}
#Override
public void unselect() {
selection.remove(hit);
}
}
Everything renders fine, but I get an error when trying to submit:
Caused by: java.lang.IllegalStateException: Attempt to set model object on null model of component: form:checkgroup
at org.apache.wicket.Component.setDefaultModelObject(Component.java:3042)
at org.apache.wicket.markup.html.form.FormComponent.updateCollectionModel(FormComponent.java:1572)
at org.apache.wicket.markup.html.form.CheckGroup.updateModel(CheckGroup.java:160)
at org.apache.wicket.markup.html.form.Form$FormModelUpdateVisitor.component(Form.java:228)
at org.apache.wicket.markup.html.form.Form$FormModelUpdateVisitor.component(Form.java:198)
at org.apache.wicket.util.visit.Visits.visitPostOrderHelper(Visits.java:274)
at org.apache.wicket.util.visit.Visits.visitPostOrderHelper(Visits.java:262)
at org.apache.wicket.util.visit.Visits.visitPostOrder(Visits.java:245)
at org.apache.wicket.markup.html.form.FormComponent.visitComponentsPostOrder(FormComponent.java:422)
at org.apache.wicket.markup.html.form.Form.internalUpdateFormComponentModels(Form.java:1793)
at org.apache.wicket.markup.html.form.Form.updateFormComponentModels(Form.java:1757)
at org.apache.wicket.markup.html.form.Form.process(Form.java:913)
at org.apache.wicket.markup.html.form.Form.onFormSubmitted(Form.java:770)
at org.apache.wicket.markup.html.form.Form.onFormSubmitted(Form.java:703)
... 27 more
I think its some of the Ajax code breaking, since my SelectAllCheckBox button is also failing. Any ideas why? Is this even the best way to handle such a use case?
Your Checkgroup does not have a Model, thus Wicket can't copy the current state of the Model into a null object. You should use the constructor with an additional parameter representing the Model you want to store the value in.

GWT is making an unexpected event call

My code is below: I am seeing that on running the app the loadWidget method gets invoked even when the adminLink is not clicked. This is not want I want, but I'm not sure what is causing the issue. Please advise
public class LoginModule implements EntryPoint {
LoginPopup loginPopup;
private class LoginPopup extends PopupPanel {
public LoginPopup() {
super(true);
}
public void loadWidget(){
System.out.println("I am called 1");
CommonUi cUi = new CommonUi();
//#342 moved code to common area
FormPanel loginForm = cUi.getLoginFormUi();
setWidget(loginForm);
}
}
#Override
public void onModuleLoad() {
//#251 improved login popup ui.
final Anchor adminLink = new Anchor("User Login");
// final Label adminLink = new Label("User Login");
adminLink.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
// Instantiate the popup and show it.
loginPopup = new LoginPopup();
loginPopup.loadWidget();
loginPopup.showRelativeTo(adminLink);
loginPopup.show();
}
});
if(RootPanel.get("admin") !=null)
RootPanel.get("admin").add(adminLink);
}
}
Running Dev Mode, set a breakpoint in that method in your Java IDE, and take a look at the current stack, what code is calling that method. If that is the only code in your app, then this only appears to be invokable from that onClick handlers, so it is a matter of figuring out why that is being invoked.

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.