Wicket ComponentNotFoundException: Component has been removed from page - wicket

I have list with ajax link in each row. this link manage own row removeing process. whole list wrapped with WebMarkupContainer.
By pressing the link, called next logic
1) item removed from DB.
2) updated list model
3) target.add(wmc) - add WebMarkupContainer to ajax for updating
since list has more then one element each remove action crashed on render stage. So after refresh page i see that action was done, but problem happened after that
IKickListener onKickListener = new IKickListener() {
#Override
public void onKickListener(ListItem<Consultant> item, AjaxRequestTarget target) {
Cons modelObject = item.getModelObject();
mUserDAO.remove(modelObject.accountId, getId());
updateListModel();
target.add(mWmc);
target.appendJavaScript("console.log("kicked")");
}
};
mWmc = new WebMarkupContainer("wmc");
mWmc.setOutputMarkupId(true);
add(mWmc);
ListView listView = new ConsListView("consList", new PropertyModel<List<? extends Cons>>(this, "consultants"), onKickListener);
mWmc.add(listView);
and populate method of my list
#Override
protected void populateItem(final ListItem<ConsPanel.Cons> item) {
item.add(new IndicatingAjaxLink("actionKick") {
private static final long serialVersionUID = 1L;
#Override
public void onClick(AjaxRequestTarget target) {
mKickListener.onKickListener(item, target);
}
});
}
then i recived next stack trace
org.apache.wicket.core.request.handler.ComponentNotFoundException: Component 'consPanelPlace:cons:wmc:consList:2:actionKick' has been removed from page.
at org.apache.wicket.core.request.handler.ListenerInterfaceRequestHandler.respond(ListenerInterfaceRequestHandler.java:177)
at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:865)
at org.apache.wicket.request.RequestHandlerStack.execute(RequestHandlerStack.java:64)
at org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:265)
at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:222)
at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:293)
at org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:261)
at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:203)
at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:284)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1081)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1566)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1523)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
I use wicket 7.0.0-M5
UPDATE
I have found, that when i have more then 1 item in list, ajax callback attached only for first one. But on click action removed all items except one. Also ajax link called items count times.

I fount the problem. I have had same id not wicket:id, but general id, at each item. so listener had attached to first one, because wicket ajax listen for it. then it had called few times.
Problem was in markup.
<span class="btn" wicket:id="actionKick" id="kick">Kick</span>
^^^^^^^^^---problem was here

Related

Reorder items in Apache Wicket's repeating views

Is it possible to reorder items that have been added to a repeating view (more precisely a ListView) in Apache Wicket?
I tried reordering them in the attached list, like shown in the following code, but this had no effect:
int indexA = itemList.indexOf(itemA);
int indexB = itemList.indexOf(itemB);
itemList.set(indexA, itemB);
itemList.set(indexB, itemA);
As this had no effect I tried resetting the list property of the ListView:
listView.setList(itemList);
Of course I remembered to trigger an according repaint for the web page, but all in all it had no effect.
In some further attempts I tried to add a new item not to the end of the list but to the beginning:
itemList.add(0, newItem);
Instead of just
itemList.add(newItem);
While the latter one works (and always worked fine), the first obviously works for the first item but throws an exception for the second item.
Last cause: Unable to find component with id 'list-component' in [ListItem [Component id = 0]]
Expected: 'list-container:list-items:0:list-component'.
Found with similar names: 'list-container:list-items:1:list-component'
Where list-container is the WebMarkupContainer surrounding the ListView, list-items is the ListView itself and list-component is the id of the item to be added.
So, is it not possible to reorder items after they have been added to a repeating view? Can new items only be added at the end of it? Or am I missing something here, probably a class different than ListView that implements such features?
My main goal is to be able to reorder items, the "add at the beginning"-approach was just a test if it would at least work to remove the items from the view and re-add them at the desired position.
The link that has 'move Up' works like this, you could use this as inspiration :)
public final Link<Void> moveUpLink(final String id, final ListItem<T> item)
{
return new Link<Void>(id)
{
private static final long serialVersionUID = 1L;
/**
* #see org.apache.wicket.markup.html.link.Link#onClick()
*/
#Override
public void onClick()
{
final int index = item.getIndex();
if (index != -1)
{
addStateChange();
// Swap items and invalidate listView
Collections.swap(getList(), index, index - 1);
ListView.this.removeAll();
}
}
#Override
public boolean isEnabled()
{
return item.getIndex() != 0;
}
};
}

upgrade from wicket 1.4.9 to wicket 1.4.22 causes button to not be triggered

We are using 1.4.9 for our current webapp. But we want to upgrade to higher 1.4.x version preferably 1.4.22(latest 1.4). The problem is that the page won't submit if AjaxButton is clicked. This is working in 1.4.9. I put breakpoint on the onSubmit of that button but it is not going there. Any insights on this? Thanks!
Here is the code:
For the button:
public abstract class SXIButton extends AjaxButton {
public SXIButton(String id, Form form) {
super(id, form);
initialize();
add(new SimpleAttributeModifier("validating", "false"));
}
}
In the java:
searchForm.add(new SXIButton("searchButton", searchForm) {
private static final long serialVersionUID = -4366670520053224476L;
#Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
LOG.info("Searching Users");
target.addComponent(userContainer);
userSearchModel.setUserCurrentUserFilter(getSessionBOUser().getCd());
UserDataProvider udp = new UserDataProvider(userSearchModel,isForSearch);
udp.setSort("cd", true);
userContainer.addOrReplace(getResultPanel(udp));
}
});
add(portlet);
portlet.add(searchForm);
in html
<input type = "submit" wicket:id = "searchButton" wicket:message="value:button.search" />
Without any code it's hard to help you out. I would first check the changelog to see if anything was changed in a later version that might causes you trouble (e.g. this ticket). If you cannot find anything obvious you might want to update first to another version which is not the latest one, to narrow down in which version your code breaks for the first time.
But those are just shots in the dark.

On click functionality of Button Inside ListView in Wicket Framework

Im populating a table using ListView component in wicket.The last column of my table is button. So for each row I'll have a button in the last column.What I'm trying to implement is onlick of the button I need to delete the appropriate row. So for this I need to get the current index of the list on click of button. How to achieve/get this ?
I would extend Ajax button and pass the row reference (item) in the constructor...then you can do anything you want..by overriding the onSubmit method
Example:
private class SpecialButton extends AjaxButton {
final Item<Object> rowItem;
public SpecialButton(final String id, final Item<Object> rowItem) {
super(id);
this.rowItem = rowItem;
}
#Override
protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
// here you cand do everything you want with the item and the model object of the item.(row)
Object object = rowItem.getModelObject();
}
}
You should replace Object from Item<Object> with your reapeater model. After creating this private class you can reuse it for every row in your repeater.
If you want to delete that row you just have to remove the model from the list used to generate the repeater and refresh the repeater container(Wicket does not allow you to refresh the repeater by adding it to the target...instead you have to add the repeater continer.)
Have a look at the repeaters Wicket Examples page to understand how to use ListView and other repeaters:
http://www.wicket-library.com/wicket-examples/repeater/
You can get the current index of the list from item.getIndex()
protected void populateItem(final ListItem<T> item) {
int index = item.getIndex();
...
Look here for inspirations on how to do it properly (without index):
Wicket ListView not refreshing

How to hide suggestions in GWT SuggestBox?

I am using GWT 2.4. I have a Suggestbox and I have a requirement to hide the suggestion list under certain cases. The context is as below.
After user selects a suggestion from suggestion list, I am populating two other text box fields, with values corresponding to the selection. For example, suppose the suggestbox contains user-names, and user selects a user-name from suggestions, then other two fields, say user address and email are populated in two other text boxes. These two fields are read only now. Then user clicks on an 'Edit' button. Now the user can edit either user- name ( ie edit in suggestion box), user address and email. It doesn't make sense to show the suggestions again when the user is editing the user-name, since the user has already selected the user and decided to edit it. In a nutshell my SuggesBox should behave as a normal text box. I tried following code, (I know hideSuggestionList() is deprecated) but its not working.
display.getSuggestBox().hideSuggestionList();
Reading the javadoc for hideSuggestionList() it is said that, "Deprecated. use DefaultSuggestionDisplay.hideSuggestions() instead". I don't know how to use DefaultSuggestionDisplay, and I'm using SuggestBox with 'MultiWordSuggestOracle'.
Thanks for helping me out!!
What you can do is simply swap the SuggestionBox with a normal TextBox when the user clicks edit and back when edit is closed. Also because if you would hide the suggestions list, it still queried from the server. By swapping the widget you don't have to care about side effects. SuggestionBox itself uses also a TextBox and thus for the user it's not visible the widget has changed.
If you don't use your own SuggestionDisplay, then this should Just Work™:
((DefaultSuggestionDisplay) suggestBox.getSuggestionDisplay()).hideSuggestions();
Here is the Solution
My Entry Point Class
public class SuggestionEntryPoint implements EntryPoint {
#Override
public void onModuleLoad() {
SuggestBoxWidget suggestBoxWidget = new SuggestBoxWidget();
RootPanel rootPanel = RootPanel.get();
suggestBoxWidget.createOracle();
suggestBoxWidget.createWidgetAndShow(rootPanel);
rootPanel.add(suggestBoxWidget);
DOM.getElementById("loader").removeFromParent();
}
}
And here is my Widget
public class SuggestBoxWidget extends Composite {
private TextBox textSuggestBox = new TextBox();
private SuggestBox suggestBox = null;
DefaultSuggestionDisplay suggestionDisplay = new DefaultSuggestionDisplay();
MultiWordSuggestOracle suggestOracle = new MultiWordSuggestOracle();
private static SuggestBoxWidgetUiBinder uiBinder = GWT
.create(SuggestBoxWidgetUiBinder.class);
interface SuggestBoxWidgetUiBinder extends
UiBinder<Widget, SuggestBoxWidget> {
}
public SuggestBoxWidget() {
initWidget(uiBinder.createAndBindUi(this));
}
public void registerEvents(){
suggestBox.addKeyUpHandler(new KeyUpHandler() {
#Override
public void onKeyUp(KeyUpEvent event) {
if(suggestBox.getText().equalsIgnoreCase("1")){
suggestionDisplay.hideSuggestions();
}
}
});
}
public void createWidgetAndShow(HasWidgets container){
suggestBox = new SuggestBox(suggestOracle,textSuggestBox,suggestionDisplay);
container.clear();
container.add(suggestBox);
registerEvents();
}
public void createOracle(){
for(int i=1;i<=100;i++){
suggestOracle.add(i+"");
}
}
}
Actually you have to create a SuggestBox with 3 Parameters to the Constructor.

How do you rebuild the GWT History stack?

I have a larger application that I'm working with but the GWT History documentation has a simple example that demonstrates the problem. The example is copied for convenience:
public class HistoryTest implements EntryPoint, ValueChangeHandler
{
private Label lbl = new Label();
public void onModuleLoad()
{
Hyperlink link0 = new Hyperlink("link to foo", "foo");
Hyperlink link1 = new Hyperlink("link to bar", "bar");
Hyperlink link2 = new Hyperlink("link to baz", "baz");
String initToken = History.getToken();
if (initToken.length() == 0)
{
History.newItem("baz");
}
// Add widgets to the root panel.
VerticalPanel panel = new VerticalPanel();
panel.add(lbl);
panel.add(link0);
panel.add(link1);
panel.add(link2);
RootPanel.get().add(panel);
History.addValueChangeHandler(this); // Add history listener
History.fireCurrentHistoryState();
}
#Override
public void onValueChange(ValueChangeEvent event)
{
lbl.setText("The current history token is: " + event.getValue());
}
}
The problem is that if you refresh the application, the history stack gets blown away. How do you preserve the history so that if the user refreshes the page, the back button is still useful?
I have just tested it with Firefox and Chrome for my application and page refresh does not clear the history. Which browser do you use? Do you have the
<iframe src="javascript:''" id='__gwt_historyFrame' style='position:absolute;width:0;height:0;border:0'></iframe>
in your HTML?
GWT has catered for this problem by providing the History object. By making a call to it's static method History.newItem("your token"), you will be able to pass a token into your query string.
However you need to be aware that any time there is a history change in a gwt application, the onValueChange(ValueChangeEvent event){} event is fired, and in the method you can call the appropriate pages. Below is a list of steps which i use to solve this problem.
Add a click listener to the object that needs too call a new page. In handling the event add a token to the history.(History.newItem("new_token").
Implement the ValueChangeHandler in the class that implements your EntryPoint.
Add onValueChangeHandler(this) listener to the class that implements the EntryPoint. Ensure that the line is add in the onModuleLoad() method (it is important it is added in this method) of the class that implements the EntryPoint(pretty obvious ha!)
Finally implement onValueChange(ValueChangeEvent event){ //call a new page } method.
That's it