0

I am currently coding a Web Application with JSF 2.3 and primefaces 11. Because we are trying to minimize duplicate code we are refactoring Facelets with composite components. This works for the most part very well, but I've encountered a problem:

I want to use a dialog (coded in a composite) to add a new contact in another composite component which displays a table of all contacts. The dialog works fine but the listener method of the confirm button is never called and I cannot figure out why.

The Dialog:

<div xmlns="http://www.w3.org/1999/xhtml"
     xmlns:p="http://primefaces.org/ui"
     xmlns:h="http://java.sun.com/jsf/html"
     xmlns:composite="http://xmlns.jcp.org/jsf/composite">

      <composite:interface>
        <composite:attribute name="contact" type="de.my.project.model.extensions.ContactOption" required="true"/>
        <composite:attribute name="confirmAction" required="true" method-signature="java.lang.Void confirm()"/>
        <composite:attribute name="widgetvar" type="java.lang.String" required="true"/>
        <composite:attribute name="appendTo" type="java.lang.String" default=""/>    </composite:interface>

    <composite:implementation>
        <!-- Dialog to add a contact. -->
        <p:dialog id="#{cc.attrs.widgetvar}" widgetVar="#{cc.attrs.widgetvar}" 
                  modal="true" appendTo="#{cc.attrs.appendTo}">
            <p:ajax event="open" update="#{cc.attrs.widgetvar}-form" resetValues="true"/>
            <p:ajax event="close" immediate="true" ignoreAutoUpdate="true"/>
            <h:form id="#{cc.attrs.widgetvar}-form">
                <!-- Hidden button, only to prevent the form submit on enter press. -->
                <p:commandButton styleClass="hidden"/>
                <div class="grid mt-1">
                    <!-- Name input -->
                    <div class="col-4 flex align-items-center">
                        <p:outputLabel value="#{msg['name']}"/>
                    </div>
                    <div class="col-8 flex align-items-center">
                        <p:inputText value="#{cc.attrs.contact.label}"
                                     required="true"
                                     maxlength="255"/>
                    </div> 
    
                    <!-- Phone number -->
                    <div class="col-4 flex align-items-center">
                        <p:outputLabel value="#{msg['phone-number']} "/>
                    </div>
                    <div class="col-8 flex align-items-center">
                        <p:inputText value="#{cc.attrs.contact.telephone}" maxlength="255"
                                     required="true"/>
                    </div>
                </div>
    
                <!-- Confirm/cancel buttons -->
                <div class="flex justify-content-end mt-2">
                    <p:commandButton value="cancel" onclick="PF('#{cc.attrs.widgetvar}').hide()"
                                     styleClass="ui-button-danger mr-2" icon="pi pi-times"/>
                    <p:commandButton value="confirm"
                                     update="@form" icon="pi pi-check"
                                     action="#{cc.attrs.confirmAction}"/>
                </div>
            </h:form>
        </p:dialog>
    </composite:implementation>
</div>

The table composite:

<div xmlns="http://www.w3.org/1999/xhtml"
     xmlns:p="http://primefaces.org/ui"
     xmlns:f="http://java.sun.com/jsf/core"
     xmlns:my="http://java.sun.com/jsf/composite/project"
     xmlns:composite="http://xmlns.jcp.org/jsf/composite"
>
    <composite:interface>
        <composite:attribute name="contactsTableId" required="true"/>
        <composite:attribute name="contactController" required="true"
                             type="de.my.project.controller.AbstractContactOptionController"/>
    </composite:interface>

    <composite:implementation>
        <p:dataTable value="#{cc.attrs.contactController.contactOptions}" var="item" id="#{cc.attrs.contactsTableId}"
                      sortMode="multiple">
    
            <!--Contact's label-->
            <p:column headerText="#{msg['label']}" sortBy="#{item.label}"
                      filterBy="#{item.label}"
                      filterMatchMode="contains" styleClass="w-auto">
                <p:outputLabel value="#{item.label}"/>
            </p:column>
    
            <!--Contact's number-->
            <p:column headerText="telephone" sortBy="#{item.telephone}"
                      filterBy="#{item.telephone}"
                      filterMatchMode="contains">
                <p:outputLabel value="item.telephone"/>
            </p:column>
    
            <!-- Action column -->
            <p:column rendered="#{request.isUserInRole('MRCC_MAINTAINER')}">
                <f:facet name="header">
                    <p:outputLabel value="actions" styleClass="block"/>
                    <!-- add button -->
                    <p:commandButton icon="pi pi-plus"
                                     value="#{msg['add-upper']}"
                                     actionListener="#{cc.attrs.contactController.initAddContact}"
                                     immediate="true"
                                     styleClass="block ui-button-success mt-2"/>
                </f:facet>
            </p:column>
        </p:dataTable>
        <my:contactDialog widgetvar="contacts-table-add-contact"
                            appendTo="body"
                            title="#{msg['contact-add']}"
                            confirmAction="#{cc.attrs.contactController.confirmContactOptionAdd()}"
                            contact="#{cc.attrs.contactController.contact}"/>
       
    </composite:implementation>

The bean with the initAddContact() and the confirmContactOptionAdd() methods:

@Named
@ViewScoped
public class ContactOptionController extends AbstractContactOptionController {
    /**
     * ID/widget var of the add dialog.
     */
    @Getter
    private static final String ADD_DIALOG_ID = "c";

    /**
     * The {@link ContactOption}s.
     */
    @Getter
    @Setter
    private List<ContactOption> contactOptions;
    
    /**
     * The filtered {@link ContactOption}s.
     */
    @Getter
    @Setter
    private List<ContactOption> filteredContactOptions;
    
    @Inject
    private ContactOptionService contactOptionService;
    
    /**
     * Contact option to add.
     */
    @Getter
    @Setter
    private ContactOption contact;
    
    /**
     * Initialises the contact add dialog.
     */
    public void initAddContact() {
        contact = new ContactOption();
        contactType = null;
        PrimeFaces.current().executeScript("PF('" + ADD_DIALOG_ID + "').show()");
    }
    
    /**
     * Delegates a new {@link ContactOption} to Persistence.
     */
    @Override
    @DisplayDomainFault
    public void confirmContactOptionAdd() {
        contactService.add(contact);
        contact = new ContactOption();
        PrimeFaces.current().executeScript("PF('" + ADD_DIALOG_ID + "').hide()");
    }
}

The problem seems to be connected to the nested composites or theappendTo parameter because I can get it to work, when the dialog is not called in another composite and is included in <Ui:define name="bodyEnd"> with appendTo not being set. I hope somebody can help.

Jasper de Vries
  • 19,370
  • 6
  • 64
  • 102
yfb99
  • 1
  • 1

0 Answers0