Wicket form and back button issue - java

I do not know if I missed something but I have following problem.
I am using wicket 6.5.0, i have simple form there with one field. Submitting the form redirect me on the other page. When I press the back button on my browser (firefox 14) i go back to my form, but it is empty. I would like to see it in the state i submitted it.
I also noticed that if i am on the first page with form, i have version /?0. Submitting take me to the page with version /second?2, the back button take me back to the page with version /?0.
Why is this happening? why i am skipping version ?1 ?
here is my code:
WicketApplication.java
public class WicketApplication extends WebApplication
{
#Override
public Class<? extends WebPage> getHomePage()
{
return HomePage.class;
}
#Override
public void init()
{
super.init();
mountPage("second", SecondPage.class);
}
}
HomePage.java :
public class HomePage extends WebPage {
private static final long serialVersionUID = 1L;
public HomePage(final PageParameters parameters) {
super(parameters);
add(new SimpleForm("form"));
}
public final class SimpleForm extends Form<Void>
{
private static final long serialVersionUID = -562538189475312724L;
private final ValueMap properties = new ValueMap();
public SimpleForm(final String id)
{
super(id);
add(new TextField<String>("field", new PropertyModel<String>(properties, "field")));
}
#Override
public final void onSubmit()
{
setResponsePage(new SecondPage(getPageParameters()));
}
}
}
HomePage.html
...
<form wicket:id="form">
<input type="text" wicket:id="field" value="" size="50" /> <input
type="submit" value="submit" />
</form>
...
Thank you for your replies.

When you submit, because the model has changed, the page is dirtied and wicket increases the version of the page and adds it to the Page Manager. So there is a version 1 created that you could get to by plugging in ?1. If you try it out you should see the expected value in the html wicket is sending back.
You could get around this by overriding isVersioned on your page, returning false.
From Component - isVersioned():
If a Page is not versioned then it wont track changes in its components and will use the same Page#getPageId() during its lifetime
Meaning it will serialize the dirtied page against the existing page id.

Related

AjaxFormComponentUpdatingBehavior not working in Wicket 8

I'm switching from Wicket 6 to Wicket 8, and AjaxFormComponentUpdatingBehavior doesn't seem to work anymore.
Example page:
public HomePage() {
final Form<Void> form = new Form<>("form");
final TextField<String> txt = new TextField<>("txt", new Model<>());
txt.add(new AjaxFormComponentUpdatingBehavior("onchange") {
private static final long serialVersionUID = 1L;
#Override
protected void onUpdate(final AjaxRequestTarget target) {
System.out.println("update: " + txt.getValue());
}
});
form.add(txt);
add(form);
}
and corresponding html:
<form wicket:id="form">
<input wicket:id="txt">
</form>
In Wicket 8.5.0, the onUpdate method never gets called, and there is no error message. In Wicket 6 it works fine. The same thing happens with other component types, e.g. select/DropDownChoice.
Is this a bug? Or what am I doing wrong?
The events prefixed with on have been deprecated since Wicket 6. In Wicket 8, support for them has been removed. You can get these components to work again by changing onchange to change.
See also: https://cwiki.apache.org/confluence/display/WICKET/Migration+to+Wicket+8.0

Wicket: Panel nesting as component

Is it possible (or what is the best way) to have own Panel with Component behaviours? Especially with HTML nesting...
I want something like that:
public HeaderPanel(String id) { /* extends Wicket Panel */
super(id);
add(new Link(ID_HOME_LINK, null) {
private static final long serialVersionUID = 1L;
{
add(new Image(ID_HOME_LOGO, new ContextRelativeResource("img/logo.png")));
}
#Override
public void onClick(AjaxRequestTarget target) {
setResponsePage(((BasicPage)getPage()).getLogoLinkPage());
}
});
}
With HTML:
<!DOCTYPE html>
<html>
<body>
<wicket:panel>
<a wicket:id="home-link">
<img wicket:id="home-logo" src="img/logo.png" title="LearnMe" style="max-height: 65px;" /> <!-- HERE is problem - I would like to set children here -->
</a>
</wicket:panel>
</body>
</html>
And this is the intent in Link (it is my "customized" panel that handles links):
public Link(String id, IModel<String> model, boolean ajax) { /* Extends Wicket Panel */
super(id);
this.ajax = ajax;
this.model = model;
setRenderBodyOnly(true);
if (ajax) {
add(link = new AjaxLink<String>(ID_LINK) {
#Override
public void onClick(AjaxRequestTarget target) {
Link.this.onClick(target);
}
});
} else {
add(link = new org.apache.wicket.markup.html.link.Link<String>(ID_LINK) {
#Override
public void onClick() {
Link.this.onClick(null);
}
});
}
}
With appropriate HTML:
<html>
<body>
<wicket:panel>
<a wicket:id="link"></a> <!-- HERE is problem - I don't know, which ones and how many components go there -->
</wicket:panel>
</body>
</html>
Now I get this Exception:
Last cause: Close tag not found for tag: <a wicket:id="home-link" id="home_link3">. For Components only raw markup is allow in between the tags but not other Wicket Component. Component: [Link [Component id = home-link]]
Maybe I am wrong with Panel capacibility or doing unnecessary thing with Link component, but I am looking for idea of nesting/inheriting Panels in one template like it is usual with Components in Wicket (like HeaderPanel Link were Wicket Link, not my customized Panel "Link" - that works, but it is not "common" solution).
Your problem is in Link.html. There you have a <a wicket:id="link" for the Wicket's Link but you do not have HTML element for the image. The one defined in HeaderPanel.html is completely overridden by the markup provided by (your) Link.html.

How to avoid WSOD (blank screen) while loading long-running initialization data in Struts2?

I need to do the following:
User logs in.
Redirected to welcome screen.
Looks at the welcome screen while lots of records are loaded.
Redirected to the working screen.
I am looking for a way to do in Action class something like this:
public class LinkAction extends ActionSupport implements SessionAware {
#Autowired
private ServiceDelegate myService;
public String welcome()
{
new Runnable() {
#Override
public void run() {
myService.getLoadsOfData();
//redirect to the next action
}
}.run();
// this is where the user
// goes to look at the welcome screen
return "welcome";
}
}
May be it's a wrong approach, please tell if so, I am new at Struts.
The right way is the one already suggested by AleksandrM in comments: open the page, show an indicator while you call an ajax action (let's say with jQuery, for convenience), then render the result and remove the indicator. It's easier than you think:
public class MainAction extends ActionSupport {
public String execute() {
return SUCCESS;
}
}
public class AjaxAction extends ActionSupport {
#Autowired
private ServiceDelegate myService;
private Stuff myStuff; // with getter
public String execute() {
myStuff = myService.loadLongStuff();
return SUCCESS;
}
}
Your AJAX action can either return JSON data, a JSP snippet or a Stream of binary data. Choose the way you prefer. For example, if you map SUCCESS of AjaxAction to a JSP snippet, your JSP snippet will be:
ajaxSnippet.jsp
<%# taglib prefix="s" uri="/WEB-INF/struts-tags.tld" %>
Stuff: <s:property value="myStuff" />
Then in your main.jsp, show the indicator in the div you will overwrite with the AJAX call's result:
main.jsp
<body>
<div id="main">
<img src="/images/mesmerizingProgressBar.gif" />
</div>
<script>
$(function(){ // onDocumentReady...
$.ajax({ // call ajax action...
type : 'GET',
url : '/ajaxAction.action',
success : function(data,textStatus,jqXHR){
// then render your result in "main" div,
// overwriting the loading GIF
$("#main").html(data);
},
error : function(jqXHR, textStatus, errorThrown){
$("#main").html("Error ! " + textStatus);
}
});
});
</script>
</body>
Thank you for the AJAX idea.
However, the answer I was looking for was in fact Struts interceptor "execAndWait".
I decided to use it over AJAX because I am dealing with existing application and all the Struts plumbing is in place.
This is the Struts guide on this

Customizing IndicatingAjaxLink in wicket

in my current project i've faced a problem of customizing IndicatingAjaxLink in wicket, is there any solution to change standart gif image to my own?
For example we have following listeneer
add(new IndicatingAjaxLink("closeReceivedBillspanel") {
public void onClick(AjaxRequestTarget art) {
// some timeconsuming calculations
}
});
as user clicks this link, the gif with loading appears, and i want to change this gif, is there any solution for this problem?
Have your page implements the IAjaxIndicatorAware interface
public class BasePage extends WebPage implements IAjaxIndicatorAware {
public BasePage(final PageParameters parameters) {
// Home link
AjaxLink<Page> homeLink = new AjaxLink<Page>("homeLink") {
private static final long serialVersionUID = 1L;
#Override
public void onClick(AjaxRequestTarget target) {
setResponsePage(HomePage.class);
}
};
add(homeLink);
}
#Override
public String getAjaxIndicatorMarkupId() {
return "indicator";
}
This way, you can set, in the html, any image you want to display when the loading appears by changing the image in the "img" tag
<div id="indicator" style="display: none;">
<div class="indicator-content">
Please wait... <wicket:link><img src="images/loading.gif" width="16" height="16" alt="loading" /></wicket:link>
</div>
</div>
Create yoru own custom class like, (copy whats inside IndicatingAjaxLink and update)
public class MyIndicatingAjaxLink<T> extends AjaxLink<T> implements IAjaxIndicatorAware {
private final MyAjaxIndicatorAppender indicatorAppender = new MyAjaxIndicatorAppender();
.
//rest of the code is same as IndicatingAjaxLink class
.
}
Also you need a custom AjaxIndicatorAppender within your customIndicatingAjaxLink and you need to override below method of indicatorAppender to return path of your custom image
protected CharSequence getIndicatorUrl()

Wicket - Replace Label By TextField and vice versa

I am trying to replace a Label by a TextField in a ListView. I saw a similar wicket example few weeks ago over internet, but I don't remember the link. I have added AjaxEventBehavior - "onDblClick" to the ListItem by which I want to replace a Label by a TextField and also added AjaxFormComponentUpdatingBehavior - "onBlur" to the TextField such that the TextField will be replaced by Label. Somehow it is not working. The List model for the ListView contain only {"aaaaaaaaaaaaa", "bbbbbbbbbbbbbbbb", "cccccccccccccc"} [as I am testing it] so the first Label will be "aaaaaaaaaaaaa", if I double click on this Label the TextField is appearing the place of the Label "cccccccccccccc", which is unexpected. And also the "onBlur" event is not working. Hope I can explain the problems. The code is given below:
public class TaskTypeSettingsPage extends BasePage implements Serializable {
private String val;
public TaskTypeSettingsPage() {
add(new TaskTypeSettingsForm("form"));
}
public void setVal(String val) {
this.val = val;
}
public String getVal() {
return val;
}
private class TaskTypeSettingsForm extends Form {
private static final long serialVersionUID = 10058L;
private Fragment labelFragment;
private Fragment textFragment;
public TaskTypeSettingsForm(String id) {
super(id);
setOutputMarkupId(true);
ListView listView = new ListView("row", Arrays.asList("aaaaaaaaaaaaa", "bbbbbbbbbbbbbbbb", "cccccccccccccc")) {
#Override
protected void populateItem(ListItem item) {
String str = (String) item.getModelObject();
item.add(new Label("listLabel", str));
item.setOutputMarkupId(true);
labelFragment = new Fragment("frag", "labelFragment", this.getPage());
Label label = new Label("label", str);
label.setOutputMarkupId(true);
labelFragment.setOutputMarkupId(true);
labelFragment.add(label);
item.add(labelFragment);
textFragment = new Fragment("frag", "textFragment", this.getPage());
TextField text = new TextField("text", new PropertyModel(TaskTypeSettingsPage.this, "val"));
text.setOutputMarkupId(true);
textFragment.setOutputMarkupId(true);
textFragment.add(text);
item.add(new AjaxEventBehavior("onDblClick") {
#Override
protected void onEvent(AjaxRequestTarget target) {
labelFragment.replaceWith(textFragment);
labelFragment = textFragment;
target.addComponent(textFragment);
}
});
text.add(new AjaxFormComponentUpdatingBehavior("onBlur") {
#Override
protected void onUpdate(AjaxRequestTarget target) {
textFragment.replaceWith(labelFragment);
textFragment = labelFragment;
target.addComponent(labelFragment);
}
});
}
};
add(listView);
}
}
}
And
<html>
<body>
<wicket:extend>
<div class="heading"><wicket:message key="extras.taskType" /></div>
<form wicket:id="form" autocomplete="off">
<table>
<tr wicket:id="row">
<td>
<span wicket:id="frag"></span>
</td>
</tr>
</table>
<wicket:fragment wicket:id="labelFragment"><span wicket:id="label"></span>
</wicket:fragment>
<wicket:fragment wicket:id="textFragment"><input type="text" wicket:id="text">
</wicket:fragment>
</form>
</wicket:extend>
</body>
</html>
Any information or example code will be very helpful to me. Thank you.
Edit: I found the link: example but the source code is not available.
You can replace an entire component, but you also have to consider that the same markup might not work for both a label and a text field. But you can always replace a fragment with another fragment, so if you wrap your field and label in a fragment each, you can switch between them anytime.
However you're better off using a dedicated component for this purpose, I seem to remember an Ajax field component in either core Wicket or Wicket Extensions that did it. It is called AjaxEditableLabel
The example you are trying to remember might be this editable label example.
There is a Visural Wicket library that has ViewOrEdit component. It sounds something like you are looking for.
The ListView component may not be the best basis for a form. See http://wicketinaction.com/2008/10/building-a-listeditor-form-component/

Categories