AjaxFormComponentUpdatingBehaviour issue after Form submitting in Wicket - java

I have such problem with Wickets AjaxFormComponentUpdatingBehaviour. When you set this to some components on the form, and add validation to them, after you press "Submit form" button, and, lets say, you get an error, that your component has not passed validation, after that ajax is behaving different, does not update models.
Here is code example:
TextField someText = new TextField("someTextId");
someText.setRequired(true); //added validation on requireness
CheckBox checkBx = new CheckBox("checkBxId");
TextField changeableTxt = new TextField("changeableTxtId");
changeableTxt.setEnabled(false);
checkBx.add(new AjaxFormComponentUpdatingBehaviour("onclick"){
protected void onUpdate(AjaxRequestTarget target) {
if(compoundModel.isCheckBx()){
changeableTxt.setEnabled(true);
target.addComponent(changeableTxt);
}else{
compoundModel.setChangeableTxt(null);
changeableTxt.setEnabled(false);
target.addComponent(changeableTxt);
}
}
});
Form form = new Form("form", compoundModel);
form.add(someText, checkBx, changeableTxt);
add(form);
So if check the checkBx, input some value to changeableTxt, leave someText empty and press submit button, error will appear, that field someText is required. After that, if we click on checkBx, it will make changeableTxt field disabled, but it will leave before the input value inside, instead of null.

Well let's start with explaining why you might think your code is working:
The AjaxFormComponentUpdatingBehavior will update the model of your CheckBox but only this model. That means that the changeableTxt will even stay empty if you remove the code line compoundModel.setChangeableTxt(null);
So if the Checkbox is supposed to change the value of the changeableTxt TextField it should submit the value it has while clicking it as well. You can achieve this by wrapping a Form around checkBx and changeableTxt and submit this form when click on the CheckBox by using a AjaxFormSubmitBehavior.
public class TestingPanel extends Panel {
public TestingPanel(String id) {
super(id);
final CompoundModel compoundModel = new CompoundModel();
final Form<CompoundModel> form = new Form<CompoundModel>("form",
new CompoundPropertyModel<CompoundModel>(compoundModel)) {
#Override
protected void onValidate() {
System.out.println("validate: "
+ compoundModel.getChangeableTxt());
System.out.println("validate: "
+ getModel().getObject().getChangeableTxt());
super.onValidate();
}
};
form.setOutputMarkupId(true);
add(form);
TextField someText = new TextField("someText");
someText.setRequired(true); // added validation on requireness
final CheckBox checkBx = new CheckBox("checkBx");
final TextField changeableTxt = new TextField("changeableTxt");
changeableTxt.setOutputMarkupId(true);
changeableTxt.setEnabled(false);
Form checkBoxForm = new Form("checkBoxForm");
form.add(checkBoxForm);
AjaxFormSubmitBehavior submitBehavior = new AjaxFormSubmitBehavior(
checkBoxForm, "onclick") {
#Override
protected void onSubmit(AjaxRequestTarget target) {
if (checkBx.getModelObject() == true) {
changeableTxt.setEnabled(true);
target.add(changeableTxt);
} else {
compoundModel.setChangeableTxt(null);
changeableTxt.setEnabled(false);
target.add(changeableTxt);
}
}
#Override
protected void onError(AjaxRequestTarget target) {
}
};
checkBx.add(submitBehavior);
checkBoxForm.add(checkBx, changeableTxt);
AjaxFormComponentUpdatingBehavior updateBehavior = new AjaxFormComponentUpdatingBehavior(
"onclick") {
protected void onUpdate(AjaxRequestTarget target) {
if (compoundModel.isCheckBx()) {
changeableTxt.setEnabled(true);
target.addComponent(changeableTxt);
} else {
// compoundModel.setChangeableTxt("");
changeableTxt.setEnabled(false);
target.add(changeableTxt);
}
}
};
form.add(someText);
FeedbackPanel feedbackPanel = new FeedbackPanel("feedbackPanel");
form.add(feedbackPanel);
AjaxSubmitLink submit = new AjaxSubmitLink("submit", form) {
#Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
target.add(form);
}
#Override
protected void onError(AjaxRequestTarget target, Form<?> form) {
target.add(form);
}
};
add(submit);
}
class CompoundModel implements Serializable {
private boolean checkBx = false;
private String someText = null;
private String changeableTxt = null;
public boolean isCheckBx() {
return checkBx;
}
public void setCheckBx(boolean checkBx) {
this.checkBx = checkBx;
}
public String getSomeText() {
return someText;
}
public void setSomeText(String someText) {
this.someText = someText;
}
public String getChangeableTxt() {
return changeableTxt;
}
public void setChangeableTxt(String changeableTxt) {
this.changeableTxt = changeableTxt;
}
}
}
with the following html:
<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org">
<wicket:panel>
<form wicket:id="form">
<div wicket:id="feedbackPanel" />
<input type="text" wicket:id="someText" /><br />
<form wicket:id="checkBoxForm">
<input type="checkbox" wicket:id="checkBx" /><br />
<input type="text" wicket:id="changeableTxt" /><br />
</form>
</form>
<a wicket:id="submit">submit</a>
</wicket:panel>

Related

Vaadin add values to list

I would like to have this functionality in my program:
I will have a user input field. When the user pressed the button, it will be added to the list, and input will be shown to the user.
The problem is, I would like to deselect/remove those input if the user wants. I could not achieve this.
Here is the code I have written so far, I have removed some functionality unnecessary for the question's scope:
public class AddUserInput extends VerticalLayout{
// The user input will be added to the this list
// later, this list will be sent to the server for some verification
private List<String> emails;
private HorizontalLayout content;
private VerticalLayout rows;
// user input field
private TextField emailField = new TextField("Enter email address");
public AddUserInput() {
content = new HorizontalLayout();
rows = new VerticalLayout();
content.setMargin(true);
Button addToListButton= new Button("Add to list");
addToListButton.addClickListener(new Button.ClickListener() {
#Override
public void buttonClick(Button.ClickEvent event) {
// When the user clicks add to list button
// The raw input will be added to the emails list
// The UI component is added to 'rows' component
rows.addComponent(addNewRow(emailField.getValue()));
}
});
content.addComponents(emailField, addToListButton, rows);
addComponent(content);
}
public Component addNewRow(String email){
HorizontalLayout newRow = new HorizontalLayout();
Button deleteRowButton = new Button("-");
deleteRowButton.addClickListener(new Button.ClickListener() {
#Override
public void buttonClick(Button.ClickEvent event) {
// I can delete from the UI by using the code below
newRow.removeAllComponents();
rows.removeComponent(newRow);
// How to remove from the email list???
}
});
emails.add(emailField.getValue());
Label lastEmail = new Label(emailField.getValue());
emailField.clear();
newRow.addComponents(lastEmail,deleteRowButton);
return newRow;
}
}
Is there any component/library that does this functionality?
I only need a text field, and adding the input to the list, and removing the list item if a user wants to.
The visualization of the code above:
You could use the NativeSelect component for managing the entered Strings.
I modified your AddUserInput-Component to use a NativeSelect and a corresponding DataProvider:
public class AddUserInput extends VerticalLayout {
private HorizontalLayout content = new HorizontalLayout();;
private NativeSelect<String> select = new NativeSelect<>("The List");
private ListDataProvider<String> dataProvider = DataProvider.ofCollection(new ArrayList<>());
private Button addToListButton= new Button("Add to list");
private Button deleteFromListButton = new Button("-");
private TextField emailField = new TextField("Enter email address");
public AddUserInput() {
select.setVisibleItemCount(5);
select.setWidth("100px");
select.setDataProvider(dataProvider);
select.setEmptySelectionAllowed(false);
deleteFromListButton.setEnabled(false);
content.setMargin(true);
addToListButton.addClickListener(new Button.ClickListener() {
#Override
public void buttonClick(Button.ClickEvent event) {
addEmailToList(emailField.getValue());
}
});
deleteFromListButton.addClickListener(new Button.ClickListener() {
#Override
public void buttonClick(Button.ClickEvent clickEvent) {
select.getSelectedItem().ifPresent(selectedItem -> removeSelectedEmailFromList());
}
});
select.addValueChangeListener(new HasValue.ValueChangeListener<String>() {
#Override
public void valueChange(HasValue.ValueChangeEvent<String> valueChangeEvent) {
deleteFromListButton.setEnabled(select.getSelectedItem().isPresent());
}
});
content.addComponents(emailField, addToListButton, select, deleteFromListButton);
addComponent(content);
}
private void addEmailToList(String email){
dataProvider.getItems().add(email);
select.getDataProvider().refreshAll();
emailField.clear();
}
private void removeSelectedEmailFromList(){
select.getSelectedItem().ifPresent(selectedItem -> dataProvider.getItems().remove(selectedItem));
select.setSelectedItem(dataProvider.getItems().isEmpty() ? null : dataProvider.getItems().iterator().next());
select.getDataProvider().refreshAll();
}
}
It looks like the following:
Would that be a possible option for you?

How to hide a WebMarkUpContainer checking an AjaxCheckBox in Wicket

OK basically I have a WebMarkUpContainer which contains a DateTextField component and I want to make it visible only when I check an AjaxCheckBox.
In general my code is:
private static final class Results extends BootstrapForm<ResultsModel>
{
final AjaxCheckBox isExamsSuccess = new AjaxCheckBox("isExamsSuccess") {
private static final long serialVersionUID = 1L;
#Override
protected void onUpdate(AjaxRequestTarget target) {
updateModel();
toggleStep(target);
}
};
final WebMarkupContainer wmc = new WebMarkupContainer("wmc");
final DateTextField startDate = new DateTextField("startDate",
new DateTextFieldConfig()
.autoClose(true).withFormat("dd/MM/yyyy")
.withLanguage("el").withEndDate(new DateTime()));
public Results(String id, CompoundPropertyModel<ResultsModel> propertyModel)
{
super(id, propertyModel);
add(isExamsSuccess);
wmc.add(startDate);
add(wmc);
protected void toggleStep(AjaxRequestTarget target) {
if(isExamsSuccess.getModelObject() == true){
isExamsSuccess.setModelObject(true);
wmc.setVisible(true);
target.add(wmc);
}
else {
wmc.setVisible(false);
target.add(wmc);
}
}
}
I would really appreciate some help
Your code looks good! You just need to set the initial visibility of wmc to depend on isExamsSuccess:
wmc = new WebMarkupContainer("wmc") {
#Override public void onConfigure() {
super.onConfigure();
setVisible(isExamsSuccess.getModelObject());
}
}
wmc.setOutputMarkupPlaceholderTag(true);
In addition you need to call setOutputMarkupPlaceholderTag(true) because Wicket needs to be able to find the HTML element to turn the visibility from off to on.

Wicket, how to get data line index number

When a user clicks on the edit link in a wicket data grid component, a new window would open and they would modify whatever appears on the new form. In the datagrid, there are many rows. How can I get the index number of the row I want to edit? Please see below, the onclick event of the “edit” link.
columnList.add(new AbstractLinkColumn<MyModel>(new Model<String>("Edit")) {
#Override
protected AbstractLink newLink(String componentId, final IModel<MyModel> rowModel) {
return new AjaxLink<String>(componentId, getDisplayModel()) {
#Override
public void onClick(AjaxRequestTarget target) {
ModalWindow myModelWindow = requestForm.getmyModelWindow();
MyPanel panel = new MyPanel(myModelWindow.getContentId(), requestForm
.getModelObject(), myModelWindow, rowModel.getObject(), false, isSetReadOnly);
myModelWindow.setContent(panel);
Ricola.refresh(target, panel);
myModelWindow.show(target);
}
};
}
#Override
protected Label newLinkLabel(String componentId, IModel<MyModel> rowModel) {
return new Label(componentId, getDisplayModel());
}
}.setTooltip(new Model<String>("Click the Edit link to edit the line")));
public class MyColumn extends AbstractColumn {
#Override
public void populateItem(Item item, String componentId, IModel model) {
Item rowItem = item.findParent(Item.class);
int rowIndex = rowItem.getIndex();
...
}
}

Update one Wicket Panel from clicking an item in another Wicket Panel

I have looked at many update Panel answers in SO but could not solve my problem. It is very straight forward and I don't know why I dont get the panel updated.
I have two panel created in the RadioChoicePage.java:
public class RadioChoicePage extends ApplicationPageBase{
private static final long serialVersionUID = 1L;
public TestPanel tp;
public static TextPanel txp;
public RadioChoicePage(){
tp = new TestPanel("testPanel");
txp = new TextPanel("textPanel");
txp.setMsg("Before");
add(tp);
add(txp);
}
}
The markup file looks like the following:RadioChoicePage.html
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >
<body>
<wicket:extend>
<div wicket:id="testPanel" style="position:absolute; left:10px ; width:50%; z-index:10;">
</div>
<div wicket:id="textPanel" style="position:absolute; left:450px; width:50%; z-index:5">
</div>
</wicket:extend>
</body>
</html>
The two panel are TestPanel.java and TextPanel.java. I have a TestPanel.js file adding svg using d3.js and clicking on a circle I want to update the text panel.
I am able to call the wicket method from javascript and print that the circle was clicked on the console. But I am not able to update the text Panel.
Below is the code for TestPanel.java, TestPanel.html, TestPanel.js , TextPanel.java and TextPanel.html.
TestPanel.java
public class TestPanel extends Panel{
public static final JavaScriptResourceReference TEST_JS = new JavaScriptResourceReference(
TestPanel.class, "TestPanel.js");
TextPanel ttxp = new TextPanel("textPanel");
public TestPanel(String id) {
super(id);
final AbstractDefaultAjaxBehavior behave = new AbstractDefaultAjaxBehavior() {
private static final long serialVersionUID = 1L;
public void renderHead(Component component,IHeaderResponse aResponse){
super.renderHead(component, aResponse);
String componentMarkupId = component.getMarkupId();
String callbackUrl = getCallbackUrl().toString();
aResponse.render(JavaScriptReferenceHeaderItem.forReference(TEST_JS));
aResponse.render(JavaScriptReferenceHeaderItem.forReference(D3Reference.D3_JS));
aResponse.render(OnDomReadyHeaderItem.forScript("draw(" + componentMarkupId + ",\"" + callbackUrl + "\")"));
}
protected void respond(final AjaxRequestTarget target) {
//target.add(new Label("msg", "Yeah I was just called from Javascript!"));
System.out.println("I was succesfully clicked");
ttxp.setMsg("After");
target.add(ttxp);
}
};
add(behave);
}
}
TestPanel.html
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >
<head>
<wicket:head>
</wicket:head>
</head>
<body>
<wicket:panel>
<div id="chart" style="position:absolute; width:400px; height:400px; border:2px solid blue;"></div>
</wicket:panel>
</body>
</html>
TestPanel.js
function draw(componentMarkupId,callbackUrl){
console.log(" Draw is called!");
//Width and height
var w = 300;
var h = 100;
//Data
var dataset = [ 5, 10, 15, 20, 25 ];
//Create SVG element
var svg = d3.select("#chart")
.append("svg")
.attr("width", w)
.attr("height", h);
var circles = svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle");
circles.attr("cx", function(d, i) {
return (i * 50) + 25;
})
.attr("cy", h/2)
.attr("r", function(d) {
return d;
})
.attr("fill", "red")
.attr("stroke", "orange")
.attr("stroke-width", function(d) {
return d/2;
});
circles.on("click",function(d){
this.style.stroke = "steelblue";
$(function() {
var wcall = Wicket.Ajax.get({ u:callbackUrl });
//var wcall = wicketAjaxGet('$callbackUrl$');
alert(wcall);
});
});
}
TextPanel.java
public class TextPanel extends Panel{
String msg;
boolean initialize = true;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public TextPanel(String id) {
super(id);
// TODO Auto-generated constructor stub
System.out.println(getMsg());
if(initialize){
setMsg("Before");
initialize = false;
}
Label mmsg = new Label("msg", getMsg());
add(mmsg);
setOutputMarkupId(true);
}
}
TextPanel.html
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >
<head>
<wicket:head>
</wicket:head>
</head>
<body>
<wicket:panel>
<div wicket:id="msg" style="border: 2px solid blue;"></div>
</wicket:panel>
</body>
</html>
Please do give me a solution with explanation. As I have read so many solutions and explanations on SO and other resources but I feel im missing something basic here.
You can copy the code exactly and run it to check whats the real problem. I do not get any errors but Panels simple dont get updated.
Thank you for taking time to read this huge question with a small problem.
RadioChoicePage's textPanel should not be static, otherwise the component will be shared between multiple sessions:
public TextPanel txp;
Why is TestPanel creating its own instance of TextPanel?
TextPanel ttxp = new TextPanel("textPanel");
Remove that! Add a hook method to TestPanel instead:
protected void onClicked(AjaxRequestTarget target) {
}
final AbstractDefaultAjaxBehavior behave = new AbstractDefaultAjaxBehavior() {
protected void respond(final AjaxRequestTarget target) {
onClicked(target);
}
}
Let RadioChoicePage decide what to do when anything is clicked:
tp = new TestPanel("testPanel") {
protected void onClicked(AjaxRequestTarget target) {
target.add(txp);
}
};
txp = new TextPanel("textPanel");
txp.setOutputMarkupId(true);

Container Visibility control on Change behavior of text field in Wicket 1.4

I've a container which output markup placeholder tag is set to true. I want to display it only if I digit in a certain text field a certain string. For example if I digit "show" in text field, container appears, if I digit "hide" it disappears. I made this code:
container.setOutputPlaceHolderTag(true);
container.setOuputMarkupId(true);
textfield.add(new OnChangeAjaxBehavior() {
#Override
protected void onUpdate(AjaxRequestTarget target) {
form.modelChanged();
if ("SHOW".equals(textfield.getModelObject())) {
container.setVisible(true);
} else {
container.setVisible(false);
}
target.addComponent(container);
}
this code works only if I write SHOW, BUT when I write another string it doesn't disappear. To make it disappear I've to refresh the whole form they are into (and I don't want it).
How can I solve this problem??
some details: all component I'm refering to are in a form, and only if I refresh the form setVisible(false) works. From now only setVisible(true) works, it seems the container stucks on visibility true.
This code works:
public class HomePage extends WebPage {
private static final long serialVersionUID = 1L;
private String someValue;
private WebMarkupContainer container;
public HomePage(final PageParameters parameters) {
super(parameters);
add(container = container());
add(textfield());
}
private WebMarkupContainer container() {
WebMarkupContainer wmc = new WebMarkupContainer("container") {
#Override
protected void onConfigure() {
super.onConfigure();
setVisible("SHOW".equals(someValue));
}
};
wmc.setOutputMarkupPlaceholderTag(true);
return wmc;
}
private TextField textfield() {
TextField tf = new TextField("textfield", new PropertyModel(HomePage.this, "someValue"));
tf.add(new OnChangeAjaxBehavior() {
#Override
protected void onUpdate(AjaxRequestTarget art) {
//just model update
art.add(container);
}
});
return tf;
}
}
Use
container.setOutputPlaceHolderTag(true);
container.setOuputMarkupId(true);
textfield.add(new OnChangeAjaxBehavior() {
#Override
protected void onUpdate(AjaxRequestTarget target) {
form.modelChanged();
if ("SHOW".equals(((TextField<String>) getComponent()).getModelObject())) { //change this
container.setVisible(true);
} else {
container.setVisible(false);
}
target.addComponent(container);
}
I got this tip from Getting a Wicket text box's value in an AJAX onchange event

Categories

Resources