Jaims
Jaims

Reputation: 1575

Opening multiple dialogs with PrimeFaces DF

With PrimeFaces, I'd like to open multiple different dialogs. An easy way at first seems the PrimeFaces Dialog Framework. Which does work to an extent.

I have a DataTable with records, each record can be opened into a new Dialog. For each record, opening this dialog works fine. But it seems that the Dialog seems to be bound to the id of its invoking parent.

A minimal example to demonstrate this issue is the following. Consider the following xhtml.

<h:form id="indexForm">
    <p:dataTable id="indexTable" value="#{dFDemo.indexes}" var="index">
        <p:column sortBy="#{index}" headerText="index">
            <p:commandButton id="openDialogBtn" value="Open dialog #{index}"
                             action="#{dFDemo.openDialog(index)}"/>
        </p:column>
    </p:dataTable>
</h:form>

And the following backing bean:

@ManagedBean
public class DFDemo {

    private List<Integer> indexes = Arrays.asList(1, 2, 3, 4, 5);

    public void openDialog(int index) {
        System.out.println("Opening a dialog for " + index);
        PrimeFaces.current().dialog().openDynamic("dfdemo", null, null);
    }

    // Getter & Setter
}

If I click on the first button, it opens a dialog and prints Opening a dialog for 1. Similarly, if I click the second button, it opens another dialog and prints Opening a dialog for 2.

Buttons 1 and 2 are now no longer able to open a new dialog. It does call openDynamic() on the server, but doesn't open anything. The reason I think it's linked to its parent, is because if you change the sort order and put index 5 on top, you can still not click the first row (now button 5).

I assume this is because it's linked to the rowIndex to ensure a unique ID. I can see the button is re-rendered with the onclick='PrimeFaces.ab({s:"indexForm:indexTable:0:openDialogBtn"});return false;'.

I intend to reload this table however. The contents of this table will be different, but the IDs of this table won't change. Making it impossible to open a new dialog.

I tried to append some random id to ensure uniqueness when re-rendering the table. But appending my own id causes the components to break (sorting, actions, ...).

I couldn't use the regular Dialog component with specific zone updates neither. Because it would ruin the lifecycle of the existing dialogs.

This does seem to be the default behavior of the Dialog Framework. Just as in the Dialog Framework showcase, it is not possible to open multiple dialogs from the same button.

Is it possible to have the Dialog Framework open multiple dialogs from the same source or is there a way to work around this issue?

Upvotes: 1

Views: 1214

Answers (1)

Jaims
Jaims

Reputation: 1575

To have the Dialog Framework do its thing, you need to register the appropriate ActionListener. The default ActionListener that is configured, is the org.primefaces.application.DialogActionListener. In this ActionListener, the source WidgetVar and source ClientId are put into the FacesContext.

In my case, it was sufficient to provide a custom implementation which puts a random UUID as the source component. This allowed multiple dialogs to be opened from the button which activates the Dialog.

So the following listener:

public class RandomSourceDialogActionListener implements ActionListener {

    private ActionListener base;

    public RandomSourceDialogActionListener(ActionListener base) {
        this.base = base;
    }

    @Override
    public void processAction(ActionEvent event) throws AbortProcessingException {
        Map<Object, Object> attrs = FacesContext.getCurrentInstance().getAttributes();
        attrs.put(Constants.DIALOG_FRAMEWORK.SOURCE_COMPONENT, UUID.randomUUID().toString());
        base.processAction(event);
    }
}

Is registered in the faces-config.xml:

<application>
    <action-listener>my.application.RandomSourceDialogActionListener</action-listener>
    <navigation-handler>org.primefaces.application.DialogNavigationHandler</navigation-handler>
    <view-handler>org.primefaces.application.DialogViewHandler</view-handler>
</application>

Note: Since the source component is no longer known, events such as dialogReturn are no longer handled correctly by the source component. On the other hand, the original DialogActionHandler doesn't seem to handle these events in a DataTable neither. But it might affect you when using only a single button.

Upvotes: 2

Related Questions