0

We are using Wicket and our generated pages are quiet long (a lot of vertical scrolling). Some links or form's onSubmit methods invoke just perform some actions on the database and show the same page again:

public class MyPage extends WebPage {

    public MyPage(PageParameters parameters) {
        ....

        final Form<Void> form = new StatelessForm<Void>("formId") {
            protected void onSubmit() {
                // some database stuff
                ...
                setResponsePage(getClass(), getPageParameters());
            }
        };
        ...
    }
}

How can I make the setResponsePage invocation cause the browser scroll to the form, so the page is not just showing the top? Maybe some JavaScript-injection?

Thomas S.
  • 5,804
  • 5
  • 37
  • 72

3 Answers3

4

I think a nice Wicket-y solution combines stuff that is already in Michael's answer, with a Behavior, so you can just add this to your form.

form.add( new ScrollToTopBehavior()); 

The behaviour itself would like something like this:

public class ScrollToTopBehavior extends Behavior
{

    @Override
    public void renderHead( Component component, IHeaderResponse response )
    {
        super.renderHead( component, response );
        response.render( JavaScriptHeaderItem.forReference( Application.get().getJavaScriptLibrarySettings().getJQueryReference() ) );

        component.setOutputMarkupId( true );

        String script = String.format("doSomeJavaScriptStuff('%s')", component.getMarkupId());
        response.render( OnDomReadyHeaderItem.forScript( script ) );
    }
}

UPDATE:

For scrolling to a specific ID / ANCHOR only once, you can follow this answer: https://stackoverflow.com/a/3163635/461499

Community
  • 1
  • 1
Rob Audenaerde
  • 19,195
  • 10
  • 76
  • 121
2

JS of course.

This would be something like (with JQuery usage):

var scrollPosition = $('#scrollToMarkupId').offset().top;
$('html, body').animate({ scrollTop: " + scrollPosition + " }, 'slow');

where scrollToMarkupId is wicket component's markup id, which could be obtained by calling component.getMarkupId() method.

I'm not pro in JS, so you can try to google better impl may be.


Now, about wicket:

1) As for me, I prefer AJAX invocations for such behavior ( note that if you use such approach your page won't be stateless ):

// do not override your form's `onSubmit()` method
final Form<Void> form = new Form<Void>("formId");
// adding ajax behavior with `onSubmit()` method overriding.
form.add ( new AjaxFormSubmitBehavior ("submit")
{
    protected void onSubmit ( AjaxRequestTarget target )
    {
        // your submit logic
        // then insert js, descriped above:
        target.appendJavaScript ("..." + componentToScroll.getMarkupId() + "..");
    }
});

This approach won't reload your page at all but also post your data.

/----------------------------------------------------------------------------------------------------------------------------------/

2) You also could execute JS after page loading, by overriding renderHead method:

public class YourPage extends WebPage
{
...
    @Override
    public void renderHead ( final IHeaderResponse response )
    {
        //replace `...` by your script.
        response.render ( OnDomReadyHeaderItem.forScript ( "..." );
    }
...
}

Such script will be invoked after page is renedered (and setResponsePage method will render your page). You can use this approach for any components and panels too.

Michael Zhavzharov
  • 1,727
  • 13
  • 26
0

I've now use following JavaScript injecting code:

add(new Behavior() {
    @Override
    public void renderHead(Component component, IHeaderResponse response) {
        super.renderHead(component, response);

        response.render(new HeaderItem() {
            @Override
            public Iterable<?> getRenderTokens() {
                return Collections.singletonList("javascript-anchor");
            }

            @Override
            public void render(Response response) {
                response.write("<script type=\"text/javascript\">\n");
                response.write("window.location.href='#rules';\n");
                response.write("</script>\n");
            }
        });
    }
});

Feel free to comment (I'm a complete JS-noob with only very limited experience in Wicket).

Thomas S.
  • 5,804
  • 5
  • 37
  • 72
  • 1
    Hi Thomas, this look ok. I would try to remove the hard-coded #rules, but as you use this behavior as anonymous subclass I think it is ok. – Rob Audenaerde Dec 08 '14 at 19:59
  • 1
    Also, you can use Wicket to wrap the javascript: `response.write(JavaScriptHeaderItem.forScript("win......"));` – Rob Audenaerde Dec 09 '14 at 07:47