0
votes

I'm new to JSF and primefaces. I'm using the Primefaces Dialog Framework to pop a modal terms of service agreement. The problem I'm having is that my dialogReturn event handler is not invoked when the dialog closes and the modal overlay remains on the page although the dialog itself closes. The modal overlay may be a red herring because the dialogReturn method is not invoked when the dialog is not modal either.

Here are the relevant pieces of code:

The form from which the dialog is created:

<h:form prependId="false">
<ul>
    <ui:repeat value="#{serviceEditor.service.subsystems}" var="ss">
    <li>
    <em>#{ss.name}</em> - #{ss.description}<br/>
    <ui:fragment rendered="#{identity.loggedIn}">
         <ui:fragment rendered="#{grantManager.hasAccess(ss)}">
                            (You have access to this dataset.)
             <h:commandButton value="Discontinue Access" action="#{grantManager.unrequestAccess(ss)}"/>
         </ui:fragment>
         <ui:fragment rendered="#{!grantManager.hasAccess(ss)}">
             <p:commandButton value="Request Access"
                       actionListener="#{serviceDialog.display(ss)}"
                       styleClass="btn btn-primary" >
                 <p:ajax event="dialogReturn" 
                         listener="#{serviceEditor.acceptDialogHandler}" />
             </p:commandButton>
          </ui:fragment>
...

ServiceEditor is annotated @Named @Stateful @ConversationScoped

The actionListener code for the dialog display:

  public void display (ServiceSubsystem sub)
  {
    if (sub == null)
    {
      log.error("Service Accept dialog attempt with null subservice. Lose.");
      FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Subservice Unavailable", "We seem to have misplaced that service. This has been logged for investigation.");
      RequestContext.getCurrentInstance().showMessageInDialog(message);
      return;
    }
    log.info("svcDlg: Displaying accept dialog for service: {}.{}", sub.getService().getName(), sub.getName());
    this.sub = sub;
    Map<String, Object> dlgOpts = new HashMap<>(2);
    dlgOpts.put("modal", true);
    RequestContext.getCurrentInstance().openDialog("serviceAcceptDialog", dlgOpts, null);
    log.info("svcDlg: Did that accept dialog work out?");
  }

The actionListener code for the accept command button in the dialog:

  public void accept ()
  {
    log.info("Accepted {}.{}", sub.getService().getName(), sub.getName());
...
    String destination = "/service?faces-redirect=true&uuid=" + sub.getService().getUuid();
    log.info("Sending user to: {}", destination);
    RequestContext.getCurrentInstance().closeDialog(destination);
  }

And finally the dialog return listener that is not invoked:

  public void acceptDialogHandler (SelectEvent event)
  {
     String dest = (String) event.getObject();
     log.info("Service accept dialog closed. sending here: ", dest);
     ((ConfigurableNavigationHandler) FacesContext.getCurrentInstance().getApplication().getNavigationHandler())
            .performNavigation(dest);
  }

What did I miss in the documentation? Or is this a bug?

2

2 Answers

1
votes

I think you can try to use primefaces dialog component, is simpler.

To show or close the dialog you only need to invoke it:

PF('widgetVarDialogName').hide();
PF('widgetVarDialogName').show();

You can open or close it in view actions, for example:

<p:commandButton
    value="Open dialog"
    type="button"
    onclick="PF('widgetVarDialogName').show()" />

<p:commandButton
    value="Do Action"
    action="#{myBean.myAction()}"
    oncomplete="PF('widgetVarDialogName').hide();" />

Also, you can invoke it from the bean if you want.

RequestContext.getCurrentInstance().execute("PF('widgetVarDialogName').show()");
RequestContext.getCurrentInstance().execute("PF('widgetVarDialogName').hide()");

(Remember, the dialog must be placed inside the form)

0
votes

I see you work a lot with the rendered="..." attribute. From what I experienced the <p:ajax event="dialogReturn" /> is not getting fired if itself or a parent element is not rendered.

So have a look in your public void accept() method. If you change some state so that a rendered attirbute of a parent element of the <p:ajax event="dialogReturn" /> namely rendered="#{!grantManager.hasAccess(ss)}" and/or rendered="#{identity.loggedIn}" would evaluate to false then the listener would not be executed.


EDIT

A workaround just came to my mind. One can avoid the problem with the same workaround as if you want to trigger dialog framework from a <p:menuitem /> (Primefaces Dialog Framework — dialogReturn event from menuitem).

Simply create a separate button somewhere outside of the possibly not rendered area and trigger it via javascript.

Not tested code example:

<ui:fragment 
    id="fragment" 
    rendered="#{...}">
    <h:commandButton
        id="pseudo_button"
        value="..." 
        onclick="document.getElementById('real_button').click()" />
</ui:fragment>

<h:commandButton 
    id="real_button"
    action="#{bean.realWorkHere()}"
    update="fragment"
    style="display:none;">
    <p:ajax 
        event="dialogReturn" 
        listener="#{...}" />
</h:commandButton>