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/
Related
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.
I would like to create wicket page where is displayed table with data from database, under this table, there is form which create another objects into database. When I save object, page does not refresh, so in table I cannot see new row.
If I understood it correctly, to solve this issue I have to use ajax. I found guide (https://cwiki.apache.org/confluence/display/WICKET/How+to+repaint+a+ListView+via+Ajax) and created something similar in my project, but it does not work and I can not find the reason why does it not work. I found that another people had problems that they tried to actualize just only rows/panel, but it is not my case. I do not get even any exception, just it does nothing. Could you please give me an advice?
.java file
public class ListPanel extends Panel {
private static final long serialVersionUID = 6953172817971228490L;
#SpringBean
RezervaceDao rezervaceDao;
public ListPanel(String id) {
super(id);
List<Rezervace> rezervace = rezervaceDao.getAllRezervace();
ListView listview = new ListView("rezervaceList", rezervace) {
private static final long serialVersionUID = 3659733406689720345L;
protected void populateItem(ListItem item) {
Rezervace r = (Rezervace) item.getModelObject();
item.add(new Label("casRezervace", r.getCasRezervace()));
item.add(new Label("jmeno", r.getJmeno()));
item.add(new Label("adresa", r.getAdresa()));
item.add(new Label("telefon", r.getTelefon()));
}
};
listview.setReuseItems(true);
// encapsulate the ListView in a WebMarkupContainer in order for it to
// update
WebMarkupContainer listContainer = new WebMarkupContainer("obal");
// generate a markup-id so the contents can be updated through an AJAX
// call
listContainer.setOutputMarkupId(true);
listContainer
.add(new AjaxSelfUpdatingTimerBehavior(Duration.seconds(3)));
// add the list view to the container
listContainer.add(listview);
// finally add the container to the page
add(listContainer);
}
}
.html file
<wicket:panel>
<div wicket:id="obal">
<table>
<tr>
<th>Čas návštěvy</th>
<th>Jméno a Příjmení</th>
<th>Adresa</th>
<th>Kontaktní telefon</th>
</tr>
<tr wicket:id="rezervaceList">
<td><span wicket:id="casRezervace"></span></td>
<td><span wicket:id="jmeno"></span></td>
<td><span wicket:id="adresa"></span></td>
<td><span wicket:id="telefon"></span></td>
</tr>
</table>
</div>
</wicket:panel>
The problem is in:
List<Rezervace> rezervace = rezervaceDao.getAllRezervace();
ListView listview = new ListView("rezervaceList", rezervace)
The list view initializes itself with a static list. It should instead ask the DB for new data on every refresh.
Read https://cwiki.apache.org/confluence/display/WICKET/Working+with+Wicket+models#WorkingwithWicketmodels-DynamicModels about static vs. dynamic models.
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.
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()
In a Wicket app, I have a bunch of <button> elements to which I'm attacking a Link component. Now in the onClick() method of the component I want to disable or change the style of the button. How can I do that? Calling setEnabled(false) has no effect.
Repeated uses of onClick() are operating on the same object in memory. If you're not using Ajax, you can still maintain some state in an anonymous subclass of Link. Then, you can use onBeforeRender() and onComponentTag() to change how it is displayed each time.
Link<Void> link = new Link<Void>("myLink") {
private String customCSS = null;
private boolean customEnabled = true;
public void onClick() {
if (/* test to determine disabled */) {
customCSS = "disabled";
customEnabled = false;
} else {
customCSS = null;
customEnabled = true;
}
}
#Override
protected void onComponentTag(ComponentTag tag) {
super.onComponentTag(tag);
if (customCSS != null)
tag.put("class", customCSS);
}
#Override
public boolean isEnabled() {
return super.isEnabled() && customEnabled;
}
};
AttributeModifiers (or other behaviors) aren't good for this case because, if you add them in the onClick() method, they will begin stacking on the same link for each click - since they are maintained as part of the Link's state.
Your Link can keep track of all manner of state, allowing your onClick() method to enable/disable/change/etc with repeated clicks.
You can also override onBeforeRender(), isVisible(), and other methods that are run each time the link is displayed on the page. The constructor, onConfigure(), and others are run just once, regardless of how many times you click the button.
I don't think this is an entirely good idea in Wicket. Of course it could be done by trickery, but it's far simpler to either:
Override the isEnabled() method to return a value derived from the model of the form/component.
Attach an AttributeModifier when you create the component, and use a model for it which returns a value derived as above.
Whichever you choose, the principle is to let Wicket "pull" rendering information in rather than pushing it explicitly.
The answer provided by Michael Borgwardt is nearly correct.
The problem is that you use Link. Disabled Links use <span> instead of
<a>/<button> and are surrounded with <em> by default. Using Button
component will set 'disabled' attribute in the element.
I would like to add, that you need to use HTML button element instead of <a> (link). Original answer can be counfusing, because Link and Button also exist in Wicket.
I think AjaxCallDecorator should be the class you need to use to disable/change style of the button.
The problem is that you use Link. Disabled Links use <span> instead of <a>/<button> and are surrounded with <em> by default.
Using Button component will set 'disabled' attribute in the element.
Take a look at SimpleAttributeModifier and AttributeAppender. Depending on your actual requirements one of those should do the trick. SimpleAttributeModifier adds or replaces an attribute of any HTML-Tag that has a prepresentation in wicket (replaces the css class), while AttributeAppender appends to the attributes (adds another css class). This should work for enabling/disabling buttons as well but I haven't tried that.
Example:
Label label = new Label("id", "Some silly text.")
add(label);
label.add(new SimpleAttributeModifier("class", "my-css-class");
For Ajax you'll have to add the component to the target as well.
More detailed example:
Java code:
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.model.Model;
public class DemoPage extends WebPage {
public DemoPage() {
Form form = new Form("form");
add(form);
final WebMarkupContainer wmc = new WebMarkupContainer("greenText");
form.add(wmc);
form.add(new Link("redLink"){
#Override
public void onClick() {
wmc.add(new SimpleAttributeModifier("class", "redText"));
}});
final Button boldButton = new Button("boldButton"){
#Override
public void onSubmit() {
wmc.add(new AttributeAppender("class", true, new Model<String>("boldText"), " "));
}};
form.add(boldButton);
Link disabler = new Link("buttonDisabler") {
#Override
public void onClick() {
boldButton.add(new AttributeAppender("disabled", true, new Model<String>("disabled"), " "));
}
};
form.add(disabler);
}
}
corresponding HTML:
<html>
<head>
<style>
.redText {
color: red;
}
.greenText {
color: green;
}
.boldText {
font-weight: bold;
}
</style>
</head>
<body>
<form wicket:id="form">
<div class="greenText" wicket:id="greenText">This is Green.</div><br />
Make it red<br />
<input type="submit" wicket:id="boldButton" value="Make it bold" /><br />
Disable the button
</form>
</body>
</html>