Link to last version of stateful page - wicket

I have a number of stateful pages with some state for each page. For example each page has a form that was submitted.
How can I organize a menu with links to last versions of these stateful pages? Should I store anywhere (may be in the session) reference to appropriate object for each page? If I use
onClick() { setResponsePage(MyPage.class); }
than I lose the previous state of the page. I want to link to last state of the page.

Each time the page is rendered store the page's id in the session.
int pageId = pageInstance.getPageId();
A list or stack data structure could be used to hold the identifiers.
You can implement the navigation menu using a repeater (RepeatingView or such) that creates a new link for each page id in the session.
In the link's click handler you can redirect the user as follows:
Page pageInstance = (Page) new PageProvider(pageId, null).getPageInstance();
setResponsePage(pageInstance);

pageId = this.getPageId(); // get current version of lets say a HomePage
//OnClick for Link
public void onClick()
{
WebPage homePageInstance =
(WebPage) new PageProvider(HomePage.pageId, null).getPageInstance();
setResponsePage(homePageInstance);
}
});

I make it passing int previousId parameter via constructor :
#MountPath(value = "editSomethingPage")
public class TestPage extends WebPage {
int previousPageId = 0;
public TestPage(int previousPage) {
super();
this.previousPageId = previousPage;
}
#Override
protected void onInitialize() {
super.onInitialize();
add(new Link("goBack") {
#Override
public void onClick() {
if (previousPageId != 0) {
setResponsePage((Page) AuthenticatedWebSession.get().getPageManager().getPage(previousPageId));
} else {
setResponsePage(PreviousPage.class);
}
}
});
}
}
It prevents creation of new page instance and keeps all states of page made by user.

Related

How to prevent gwt app to go to login page after page refresh?

I have a gwt app with a login page and a main page. After login app goes to main page. What i want is if i refresh the page to stay in main page and not going to login page. I have read many things and i tried History Mechanish but no result. Here is my code:
#Override
public void onSuccess(Login result) {
if (result.getLoginCount() == 1) {
final VerticalPanel userPanel = new VerticalPanel();
Anchor logout = new Anchor("logout");
logout.addStyleName("user");
logout.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
loginPanel.setVisible(true);
tablePanel.setVisible(false);
addPanel.setVisible(false);
userPanel.setVisible(false);
}
});
Label user = new Label("Hi " + usernameBox.getText());
userPanel.add(user);
user.addStyleName("user");
userPanel.add(logout);
userPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
userPanel.setVisible(true);
usernameBox.setText("");
passwordBox.setText("");
RootPanel.get("user").add(userPanel);
loginPanel.setVisible(false);
tablePanel.setVisible(true);
addPanel.setVisible(true);
History.newItem("main");
History.addValueChangeHandler(new ValueChangeHandler<String>() {
#Override
public void onValueChange(ValueChangeEvent<String> event) {
if(History.getToken().equals("main")){
loginPanel.setVisible(false);
tablePanel.setVisible(true);
addPanel.setVisible(true);
}
}
});
}
i also tried:
String historyToken = event.getValue();
if(historyToken.substring(0 , 4).equals("main")){
loginPanel.setVisible(false);
tablePanel.setVisible(true);
addPanel.setVisible(true);
} else {
loginPanel.setVisible(true);
tablePanel.setVisible(false);
addPanel.setVisible(false);
}
Is this the right way to handle page refresh with History.addValueChangeHandler? I would appreciate any help.
GWT application is a single page application. It means that if your reload page, the state of your application will be lost. What you can do, is to use local storage to store same state data, but that is not a good idea for an authentication data.
I recommend you to refactor your code in a way that the authentication is done against the back end and your GWT client will recover it's state from back end data when user refreshes the page.

Apache Wicket bookmarkable url added one additional parameter to the link, why?

my map is
mountPage("/page/#{code}/#{name}", Page.class);
but when I click on the link
localhost/page/10/toy?2
wicket add also one parameter like a counter, when I refresh the page I have
localhost/page/10/toy?3
why?
This is because your page are stateful, Wicket manages its own states to your page by appending this "counter". This way, when your user navigate backward using its browser built-in functionnality, the page is displayed has it has been previously.
If you don't want such a parameter in your URL, you'll need to dig out and eradicate every stateful component in your pages.
You can create
public class MountedMapperWithoutPageComponentInfo extends MountedMapper {
public MountedMapperWithoutPageComponentInfo(String mountPath, Class<? extends IRequestablePage> pageClass) {
super(mountPath, pageClass, new PageParametersEncoder());
}
#Override
protected void encodePageComponentInfo(Url url, PageComponentInfo info) {
}
#Override
public Url mapHandler(IRequestHandler requestHandler) {
if (requestHandler instanceof ListenerInterfaceRequestHandler) {
return null;
} else {
return super.mapHandler(requestHandler);
}
}
}
and map page on Application class like this
mount(new MountedMapperWithoutPageComponentInfo("/page/#{code}/#{name}", Page.class));

How to find out component-path

I use junit to assert the existing of wicket components:
wicketTester.assertComponent("dev1WicketId:dev2WicketId:formWicketId", Form.class);
This works for some forms. For complex structure, it is defficult to find out the path of the form by searching all html files. Is there any method how to find out the path easy?
If you have the component you can call #getPageRelativePath(). E.g.
// Supposing c is a component that has been added to the page.
// Returns the full path to the component relative to the page, e.g., "path:to:label"
String pathToComponent = c.getPageRelativePath();
You can get the children of a markup container by using the visitChildren() method. The following example shows how to get all the Forms from a page.
List<Form> list = new ArrayList<Form<?>>();
Page page = wicketTester.getLastRenderedPage();
for (Form form : page.visitChildren(Form.class)) {
list.add(form);
}
An easy way to get those is to call getDebugSettings().setOutputComponentPath(true); when initializing your application. This will make Wicket to output these paths to the generated HTML as an attribute on every component-bound tag.
It's recommended to only enable this on debug mode, though:
public class WicketApplication extends WebApplication {
#Override
public void init() {
super.init();
if (getConfigurationType() == RuntimeConfigurationType.DEVELOPMENT) {
getDebugSettings().setOutputComponentPath(true);
}
}
}
Extending the RJo's answer.
It seems that the method page.visitChildren(<Class>) is deprecated (Wicket 6), so with an IVisitor it can be :
protected String findPathComponentOnLastRenderedPage(final String idComponent) {
final Page page = wicketTester.getLastRenderedPage();
return page.visitChildren(Component.class, new IVisitor<Component, String>() {
#Override
public void component(final Component component, final IVisit<String> visit) {
if (component.getId().equals(idComponent)) {
visit.stop(component.getPageRelativePath());
}
}
});
}

Wicket model window throw error when first open in new tab by right click and then click on model window link

When i am going to one page(A) to another page(B) using Ajax link URL show like ...?wicket:interface=:58::::#
On B page i have a link for open model window.when we direct click on link of model window its working fine but when first open link in new Tab by right click and then click on model window link its throwing an error.
I am using setResponsePage( new B(variable)) for come to another page.when i am using setResponsePage(B.class) instead of setResponsePage( new B(variable)) its working fine.
Note : I don't want to use pageparameter with bookmarkable and setResponsePage.
Error is :
org.apache.wicket.WicketRuntimeException: component listForm:group:issueList:1:editStatus not found on page com.B[id = 18], listener interface = [RequestListenerInterface name=IBehaviorListener, method=public abstract void org.apache.wicket.behavior.IBehaviorListener.onRequest()]
org.apache.wicket.protocol.http.request.InvalidUrlException: org.apache.wicket.WicketRuntimeException: component listForm:group:issueList:1:editStatus not found on page com.B[id = 18], listener interface = [RequestListenerInterface name=IBehaviorListener, method=public abstract void org.apache.wicket.behavior.IBehaviorListener.onRequest()]
at ...........................
... 27 more
"editStatus" is a link name on model window.
Code that i am using Class A
class A extends WebPage {
Link<String> escalated = new Link<String>("escalated") {
public void onClick() {
setResponsePage(new B(Variables));
} };
}
class B extends WebPage {
public B(variables..) {
}
final ModalWindow model = new ModalWindow("UpdateModel");
model.setContent(new C(model,variables,model.getContentId()));
item.add(new AjaxLink<Void>(**"editStatus"**) {
public void onClick(AjaxRequestTarget target) {
model.show(target);
}
}.add(new Image("edit_icon", "image/edit.png")));
}
}
class C extends Panel {
public C(.....) {
}
}
I have solved this issue.Error was relating with state of wicket component.
Use StatelessLink instead of Link.
correct code :
class A extends WebPage {
StatelessLink escalated = new StatelessLink("escalated") {
public void onClick() {
setResponsePage(new B(Variables));
} };
}
it would also removed "...?wicket:interface=:58::::#" from url.
when we used Link,AjaxLink it would maintain state.so when we open any link in new tab it would changed state on server side(change ids of component) but on client side it would remain same. so when we click any link on same page there are no information of updated ids and it would have thrown an error.

continueToOriginalDestination does not bring me back to originating page

I am trying to sign into my application. First I throw the RestartResponseAtInterceptPageException (this is in a WicketPanel on my BasePage):
add(new Link<String>("signin") {
#Override
public void onClick() {
throw new RestartResponseAtInterceptPageException(SignIn.class);
}
});
The SignIn Page class contains a form (an inner private class) for the sign in, with the following submit button:
add(new Button("signinButton") {
#Override
public void onSubmit() {
final User user = model.getObject();
final boolean result = MySession.get().authenticate(user);
if (result) {
if (!continueToOriginalDestination()) {
setResponsePage(MySession.get().getApplication().getHomePage());
}
} else {
error("Authentication failed");
}
}
});
When this button is clicked and the user is successfully authenticated, I am not redirected to the page where I clicked on the signIn link but instead I stay on the SignIn page? I've tried debugging this, but haven't been able to find out where things go wrong.
I am glad for any hints that lead to my finding the error of my ways.
This is wicket 1.5.1 by the way.
Small Update because I got the hint I needed from the answer, there is still a bit of explaining to do. The solution looks like this:
add(new Link<String>("signin") {
#Override
public void onClick() {
setResponsePage(new SignIn(getPage()));
}
});
The SignIn class gets a constructor that takes a page obviously and I simply set that page as with setResponsePage to return to where I started without all the continueToOriginalDestination and exception throwing.
RestartResponseAtInterceptPageException is meant to be used to redirect to an interception page while rendering a page. For example, in the constructor of a Page class ProtectedPage, if there is no user signed in, you throw new RestartResponseAtInterceptPageException(SignIn.class). When the SignIn page calls continueToOriginalDestination(), the user is taken back to the original ProtectedPage destination.
Your use is not a typical use of RestartResponseAtInterceptPageException since you throw it in a link handler. Why don't you do a setResponsePage(SignIn.class) directly instead? If you really want to return to the exact page you were on when the "signin" link is clicked, you could also try changing it to:
add(new Link<String>("signin") {
#Override
public void onClick() {
setResponsePage(getPage());
throw new RestartResponseAtInterceptPageException(SignIn.class);
}
});