Wicket DropDownChoice NOT working correctly with PropertyModels - java

I have been trying to debug why my DropDownChoice in a simple form with just the DropDown and a Submit Button hasn't been working correctly for hours now.
It has a very weird behaviour. Where the first value selected in the drop down choice is sent successfully to the server after which any other choice select is not updated by the model. ie if I have a List persons, and I select the 2nd person, it submits this successfully. However, on select of another person and trying to submit it again it keeps showing the first selected option.
Snippets of code here:
ChoiceRenderer<Empowerment> empowermentChoiceRenderer = new ChoiceRenderer<>("name", "id");
final DropDownChoice<Empowerment> empowermentDropDownChoice =
new DropDownChoice<>("empowerment", new PropertyModel<Empowerment>(this, "empowerment"), empowermentList, empowermentChoiceRenderer);
empowermentDropDownChoice.setRequired(true);
add(empowermentDropDownChoice);
Only way I am able to get a decent behaviour is if I set the empowerment variable above to null. In this case, on submit the empowerment is reinitialised to null and then a new submit works correctly.
empowerment is just a JPA entity.
I'll be glad to know if this is a known issue. I experienced it in wicket 6.9.1 and wicket 6.12

Finally, found the solution to the problem. Above code is correct, but problem lied in the entity class itself - Empowerment needs to implement Equals and Hashcode correctly.
The DropDownChoice works just fine after this.

Add an OnChangeAjaxBehavior to your DropDownChoice. This will update the model value on every selection change you make on the drop down:
empowermentDropDownChoice .add(new OnChangeAjaxBehavior() {
#Override
protected void onUpdate(AjaxRequestTarget art) {
//just model update
}
});

Related

How to correct a display problem when inserting a row in a JavaFX grid?

I want to insert a new JavaFX bean in a grid using an "insert" button. Everything is fine, except for a display problem. After insertion, a "ghost selection" is displayed lower in the grid, as shown in this screenshot. In this example, a fourth section bean was added and selected as requested. But a fake selection appears 10 lines under the last real bean, where no bean is set for this row.
Has anyone experienced this kind of behavior? Any clue how get rid of this ghost selection? Here is what the code for the insert button looks like:
#FXML
private Button insert;
...
insert.setOnAction(event -> {
JfxBean newBean = createBean();
tableView.getItems().add(newBean);
int index = tableView.getItems().indexOf(newBean);
tableView.getSelectionModel().clearSelection();
tableView.requestFocus();
tableView.scrollTo(index);
tableView.getSelectionModel().focus(index);
tableView.getSelectionModel().select(index);
};
According to javaFX-8 documentation, SelectionModel.java does not expose any focus() method. FocusModel.java does instead. Therefore JVM will fail to compile your presented code.
Below is a possible solution:
insert.setOnAction(event -> {
JfxBean newBean = createBean();
tableView.getItems().add(newBean);
int index = tableView.getItems().indexOf(newBean);
tableView.getSelectionModel().clearSelection();
tableView.requestFocus();
tableView.scrollTo(index);
// below line is the amendment
tableView.getFocusModel().focus(index);
tableView.getSelectionModel().select(index);
};
Finally, adding tableView.refresh() corrected this weird behavior. No more ghost selection.

How to use (browser)autocomplete with Vaadin 10 TextField

I try to build an reservation Form with vaadin 10 while building it i encounterd the problem, that the autocompletion we know from every form on te web doesn't work. I put in an name field the name press submit an the next time i want to re-enter the name i need to write it out again.
My code looks like that (shortend):
TextField name = new TextField();
Button save = new Button("submit");
save.addClickListener(event -> save());
name.setAutocomplete(Autocomplete.ON);
add(name);
add(save);
i had the hopes that Autocomplete.On does the magic for me but it seems not to work. Maybe the way the save methode works screw things up?
the methode is rather big i just simplify it
private void save() {
--save everything to db
--remove all fields
--replace the fields with text saying reservation done
}
found out that someone created issue https://github.com/vaadin/vaadin-text-field/issues/156
seems to be an Shadow DOM limitation
Related issues:
https://bugs.chromium.org/p/chromium/issues/detail?id=746593
https://bugs.webkit.org/show_bug.cgi?id=172567
Edit:
for auto completion for my loginForm i got it working with adding
class xyz extends Div implements PageConfigurator{
...
#Override
public void configurePage(InitialPageSettings settings) {
settings.addInlineWithContents(
InitialPageSettings.Position.PREPEND,
"window.customElements=window.customElements||{};
window.customElements.forcePolyfill=true;
window.ShadyDOM={force:true};",
InitialPageSettings.WrapMode.JAVASCRIPT);
}
I came across this issue recently with Vaadin 14 and a custom login form.
Chrome only offers auto-filling fields (and also save login details) if it can see the input tags with name attributes in the Light DOM, but Vaadin creates TextFields with all of its elements inside of a Shadow DOM hidden.
Solution is to create a reference with <input slot="input"> inside the parent <vaadin-text-field> as part of Light DOM. All the styles and everything will still be in the Shadow DOM but Chrome now can see the input fields for auto-completion.
Kotlin code:
val username = TextField().apply {
element.setAttribute("name", "username")
element.appendChild(Element("input").setAttribute("slot", "input"))
}
val password = PasswordField().apply {
element.setAttribute("name", "password")
element.appendChild(Element("input").setAttribute("slot", "input"))
}
add(username, password)

Tapestry5 Ajaxformloop limit number of rows

I am trying to limit the number of rows that a user can add in an ajaxformloop.
Short example:
For example, the loop found in the tapestry 5 documentation here: http://tapestry.apache.org/5.3/apidocs/org/apache/tapestry5/corelib/components/AjaxFormLoop.html
If for example I would only like the user to be able to enter 3 phone numbers, how can that be done?
What I have tried:
1) I tried returning null from the onAddRow event, this causes an exception and the exception report page to display - these events shouldn't return null I don't think.
2) I tried adding my own add row button like this:
<p:addRow>
<t:addrowlink>Add another</t:addrowlink>
</p:addRow>
And then putting a t:if around it, like this:
<t:if test="canAddMorePhones()">
<p:addRow>
<t:addrowlink>Add another</t:addrowlink>
</p:addRow>
</t:if>
In this case, the "add another" reverts to the default "Add row" button and my add row link doesn't show.
3)I tried moving that t:if inside the , this had similar results.
--------------------------
I am sure that this is a fairly common aim, is there any simple way to do it? Perhaps someone can provide an example, and if possible this can help to go in the documentation as i'm sure i'm not going to be the only one trying to do this.
Note: I did also ask on the T5 users mailing list and had one answer but I can't seem to get it working after the response from Lance (Which I am sure is probably correct, but i'm not sure how to use the AjaxResponseRenderer as per my reply last week, this is probably due to my own technical limitations or understanding of some parts of T5).
http://apache-tapestry-mailing-list-archives.1045711.n5.nabble.com/Ajaxformloop-add-row-link-max-size-tt5730840.html
I also tried using ajaxResponseRenderer.addRender as you did in your mailing list code, but it doesn't work because it seems that Tapestry has some problems dealing with updating a component that's busy updating another component. However, AjaxResponseRenderer also supports execution of JavaScript. Taking this approach on the AjaxFormLoop example in the docs, specify the addrowlink as follows:
<p:addrow>
<t:if test="canAddMorePhones()">
<t:addrowlink id="addRowLink" t:id="addRowLink">Add another</t:addrowlink>
</t:if>
</p:addrow>
Then add the following code right before return phone; in onAddRowFromPhones():
ajaxResponseRenderer.addCallback(new JavaScriptCallback() {
public void run(JavaScriptSupport javascriptSupport) {
if (!canAddMorePhones()) {
javascriptSupport.addScript("document.getElementById('addRowLink').style.display = 'none';");
}
}
});
This example was tested successfully in Tapestry 5.3.7.

Return list of checked checkboxes from Javascript to Wicket

I am trying to make a filter for a searchfield where a number of checkboxes can be checked to choose what people want to search. I am currently trying to do this with the CheckGroup component but as I do not have a submit button I do not know how I can retrieve the latest checked objects. One thought of doing it was using Javascript, to call a function in Javascript and retrieve all the checkboxes like that. I currently have the following code in Wicket. So my question would be how to do this and if it is possible to not do this with Javascript. I have tried using AjaxFormChoiceComponentBehaviour and that works but since it does a post whenever a checkbox is checked, I think JS would be a better option.
public Filter(String id) {
super(id);
form = new Form("filterform");
types = resultItemHandlerPool.getTypes();
checkGroup = new CheckGroup<Class<?>>("checkGroup", new PropertyModel<Collection<Class<?>>>(this,"types"));
ListView typesListview = new ListView<Class<?>>("typesList", new PropertyModel<List<? extends Class<?>>>(this,"types")) {
#Override
protected void populateItem(final ListItem<Class<?>> item) {
item.add(new Check<Class<?>>("check", item.getModel()));
item.add(new Label("className", item.getModelObject().getSimpleName()));
}
};
typesListview.setReuseItems(true);
checkGroup.add(typesListview);
form.add(checkGroup);
add(form);
}
public List<Class<?>> getSearchableTypes() {
return types;
}
Thanks and kind regards,
Merlijn
You say you want to do the search server side. So, the server needs to know which items are checked in order to do the search.
Just use a plain old form for the searchfield (including checkboxes) and make it so that after entering the search-value the user posts the form. That way, the serverside code will receive the search value and the list of checked checkboxes and will know exactly what to search for.
AjaxFormChoiceComponentBehaviour does indeed update the server side Checkgroup after every click with an ajax post. If you only need to know the value of the Checkgroup after posting the search value, just don't use the AjaxFormChoiceComponentBehaviour and submit the form. Both a normal form submit and an ajax submit will work here.

Wicket ListView not refreshing

I am taking my first steps with Apache Wicket and ran into the following problem. I have a ListView that displays a "delete" link right next to its entries. When the delete link is clicked, the entity represented by the list item is deleted from the database but the list itself does not get updated until I reload the page manually in the browser.
IModel<List<SampleEntity>> sampleEntityListModel = new LoadableDetachableModel<List<SampleEntity>>() {
#Override
protected List<SampleEntity> load() {
return mSampleEntityBA.findAll();
}
};
mListview = new ListView<SampleEntity>("listview", sampleEntityListModel) {
#Override
protected void populateItem(final ListItem<SampleEntity> item) {
item.add(new Label("listlabel", new PropertyModel<String>(item.getModelObject(),
"text")));
item.add(new Link<SampleEntity>("deleteLink", item.getModel()) {
#Override
public void onClick() {
mSampleEntityBA.delete(item.getModelObject());
}
});
}
};
When onClick called, item.getModelObject() pulls from the sampleEntityListModel which in turn calls mSampleEntityBA.findAll(). The model object of sampleEntityListModel will be cached for the duration on the request cycle (until it is detached - which is usually what you want) and is not aware of the call to delete().
In order to refresh the sampleEntityListModel, add a sampleEntityListModel.detach() call just after the delete (sampleEntityListModel must be made final, but this will not cause any extra state to be serialized). This will cause the model to fetch a fresh set of data when the list view is rendered later in the request cycle.
You probably want an AjaxLink instead of that Link, and then you have to make the list refresh, using the tactics described here, possibly adjusting a bit for the fact that the wiki has Wicket 1.3 code instead of 1.4.
But you might also be better off with a different repeater, such as a RefreshingView or a DataView. There are some examples of assorted repeaters here. While none of them are exactly what you're looking for, looking at that code might help.
looks like the problem is that your mSampleEntityBA.findAll(); is returning incorrect data. hard to help without seeing more code.
on a different note, you should really be using DataView when working with database-backed lists.
You might also want to check out JQGrid from the wiQuery project instead of DataView.

Categories