简体   繁体   中英

Stateless ModalDialog in Wicket

How can I create a stateless ModalDialog using Wicket?

I tried the following code, but it results in an error. The error doesn't occur when removing the getStatelessHint() overrides, but that would make it stateful. If it's not possible, would it be possible with the deprecated ModalWindow ?

HTML:

<!DOCTYPE html>
<html>
<head>
    <style>
        .modal-dialog { border-radius: 5px; }
        .modal-dialog .modal-dialog-content { display: flex; flex-direction: column; }
        .modal-dialog-overlay.current-focus-trap .modal-dialog-content { resize: both; }
        .modal-dialog .modal-dialog-form { margin: 0; padding: 0; overflow: hidden; flex: 1; display: flex; flex-direction: column; }
        .modal-dialog .modal-dialog-header { border-radius: 5px 5px 0px 0px; background: #ffb158; margin: 0; padding-top: 4px; text-align: center; }
        .modal-dialog .modal-dialog-body { flex: 1; overflow-y: auto; padding: 20px; }
        .modal-dialog .modal-dialog-footer { padding: 5px; }
    </style>
</head>
<body>
    <a wicket:id="openModalLink">Open modal</a>

    <div id="window" wicket:id="window"></div>

    <wicket:fragment wicket:id="modalContentFragment">
        <h1>Modal Dialog</h1>
        <a wicket:id="closeModalLink">Close modal</a>
    </wicket:fragment>
</body>
</html>

Java:

package org.example.modaltest;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalDialog;
import org.apache.wicket.extensions.ajax.markup.html.modal.theme.DefaultTheme;
import org.apache.wicket.markup.html.GenericWebPage;
import org.apache.wicket.markup.html.panel.Fragment;

public class ModalPage extends GenericWebPage<Void> {
    public ModalPage() {
        ModalDialog window = new ModalDialog("window");
        window.add(new DefaultTheme());
        window.setMarkupId("window");
        window.setOutputMarkupId(true);
        add(window);

        Fragment modalContentFragment = new Fragment(ModalDialog.CONTENT_ID, "modalContentFragment", this);
        window.setContent(modalContentFragment);
        modalContentFragment.setOutputMarkupId(true);

        AjaxLink<Void> closeModalLink = new AjaxLink<Void>("closeModalLink") {
            @Override
            public void onClick(AjaxRequestTarget target) {
                target.add(window);
                ModalDialog window1 = (ModalDialog) findPage().get("window");
                window1.close(target);
            }

            @Override
            protected boolean getStatelessHint() {
                return true;
            }
        };
        closeModalLink.setOutputMarkupId(true);
        modalContentFragment.add(closeModalLink);

        AjaxLink<Void> openModalLink = new AjaxLink<Void>("openModalLink") {
            @Override
            public void onClick(AjaxRequestTarget target) {
                ModalDialog window1 = (ModalDialog) findPage().get("window");
                window1.open(target);
            }

            @Override
            protected boolean getStatelessHint() {
                return true;
            }
        };
        add(openModalLink);
    }
}

Error in Browser:

Access Denied. You do not have access to the page you requested. Return to home page

Java Exception:

16:34:16.382 [http-nio-8080-exec-4] WARN  o.a.w.c.r.h.ListenerRequestHandler - behavior not enabled; ignore call. Behavior org.apache.wicket.ajax.markup.html.AjaxLink$1@5a149041 at component [AjaxLink [Component id = closeModalLink]]
16:34:16.386 [http-nio-8080-exec-4] WARN  RequestCycleExtra - ********************************
16:34:16.390 [http-nio-8080-exec-4] WARN  RequestCycleExtra - Handling the following exception
org.apache.wicket.core.request.handler.ListenerInvocationNotAllowedException: Behavior rejected interface invocation. Component: [AjaxLink [Component id = closeModalLink]] Behavior: org.apache.wicket.ajax.markup.html.AjaxLink$1@5a149041
    at org.apache.wicket.core.request.handler.ListenerRequestHandler.invoke(ListenerRequestHandler.java:276)
    at org.apache.wicket.core.request.handler.ListenerRequestHandler.invokeListener(ListenerRequestHandler.java:222)
    at org.apache.wicket.core.request.handler.ListenerRequestHandler.respond(ListenerRequestHandler.java:208)
    at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:902)
    at org.apache.wicket.request.RequestHandlerExecutor.execute(RequestHandlerExecutor.java:63)
    at org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:283)
    at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:254)
    at org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:276)
    at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:207)
    at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:306)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:494)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:651)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:407)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:754)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1376)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:834)
16:34:16.390 [http-nio-8080-exec-4] WARN  RequestCycleExtra - ********************************

Problem is the following: Stateless links create a new page for each request. That new page does not know, that the modal dialog was opened previously. Thus the request to the nested closeModalLink is rejected, as it is not currently visible.

You'll have to transport the information about opening the dialog via the request url. Eg your closeModalLink could add a parameter to its request via #updateAjaxAttributes(), which is checked on creation of the new page and automatically opens the dialog if requested.

Here is what @svenmeier tried to explain:

  1. Use page's parameters to store the dialog state (open/closed)
  2. if the state is opened then pre-open the dialog at page creation time, so that any components/behaviors inside it are reachable in the following requests
  3. add an extra parameter to the open link to set the state
public class ModalPage extends GenericWebPage<Void> {
    public ModalPage(PageParameters parameters) {
        super(parameters);   // 1

        ModalDialog window = new ModalDialog("window");
        window.add(new DefaultTheme());
        window.setMarkupId("window");
        window.setOutputMarkupId(true);
        add(window);

        if (!parameters.get("mdOpened").isNull()) {  // 2
            window.open(null);
        }

        Fragment modalContentFragment = new Fragment(ModalDialog.CONTENT_ID, "modalContentFragment", this);
        window.setContent(modalContentFragment);
        modalContentFragment.setOutputMarkupId(true);

        AjaxLink<Void> closeModalLink = new AjaxLink<Void>("closeModalLink") {
            @Override
            public void onClick(AjaxRequestTarget target) {
                target.add(window);
                ModalDialog window1 = (ModalDialog) findPage().get("window");
                window1.close(target);
            }

            @Override
            protected boolean getStatelessHint() {
                return true;
            }
        };
        closeModalLink.setOutputMarkupId(true);
        modalContentFragment.add(closeModalLink);

        AjaxLink<Void> openModalLink = new AjaxLink<Void>("openModalLink") {
            @Override
            public void onClick(AjaxRequestTarget target) {
                ModalDialog window1 = (ModalDialog) findPage().get("window");
                window1.open(target);
            }

            @Override
            protected boolean getStatelessHint() {
                return true;
            }

            // 3
            @Override
            public void updateAjaxAttributes(AjaxRequestAttributes attributes) {
                attributes.getExtraParameters().put("mdOpened", "true");
            }
        };
        add(openModalLink);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM