jsfprimefacesdialogtypeerrorcomposite-component

p:dialog in composite component JS error: Uncaught TypeError: Cannot read property 'show' of undefined


I am trying to create a composite component to be used in my JSF 2.2 pages. Here is the composite:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
            xmlns:ui="http://java.sun.com/jsf/facelets"
            xmlns:p="http://primefaces.org/ui"
            xmlns:cc="http://java.sun.com/jsf/composite">

    <cc:interface componentType="searchUser">
        <!-- Define component attributes here -->
        <cc:attribute name="update" type="java.lang.String"
                      shortDescription="the component to update"/>
        <cc:attribute name="widgetVar" type="java.lang.String"/>
    </cc:interface>

    <cc:implementation>
        <p:dialog header="Search for User"
                  widgetVar="#{cc.widgetVar}"
                  modal="true"
                  id="searchDialog"
                >

            <p:panelGrid columns="2" id="searchPanel">
                <p:outputLabel value="First Name: "
                               for="firstname"
                        />
                <p:inputText id="firstname" value="#{SearchBean.firstname}"/>

                <p:outputLabel value="Last Name: "
                               for="lastname"
                        />
                <p:inputText id="lastname" value="#{SearchBean.lastname}"/>

                <p:commandButton value="search"/>

                <p:dataTable value="#{SearchBean.results}" var="user">
                    <p:column headerText="First Name">
                        #{user.firstName}
                    </p:column>
                    <p:column headerText="Last Name">
                        #{user.lastName}
                    </p:column>
                    <p:column headerText="E-Mail">
                        #{user.email}
                    </p:column>
                </p:dataTable>
            </p:panelGrid>
        </p:dialog>
    </cc:implementation>
</ui:composition>

and I am using it like:

 <my:searchUser update="foo" id="searchDLG" widgetVar="sdgl"/>
 <p:commandButton onclick="PF('sdgl').show();" type="button" value="search for user" />

Currently my FacesComponent Java is empty:

@FacesComponent("searchUser")
public class searchUser extends UIInput implements NamingContainer {

}

The target is to create a search form /dialog, which I can use in multiple locations.

My problem is, that on the click I get the error:

Uncaught TypeError: Cannot read property 'show' of undefined.

Any advice on what I am missing would greatly be appreciated.


Solution

  • This is not the right way to reference a composite attribute.

    <p:dialog widgetVar="#{cc.widgetVar}">
    

    It's basically referencing a property of the backing component itself.

    Composite attributes are available by #{cc.attrs} map.

    <p:dialog widgetVar="#{cc.attrs.widgetVar}">
    

    The JS error is caused because the actual widgetVar value is empty and the PF('sdgl') returned undefined on which you're then blindly trying to invoke the show() function. It's basically like a NullPointerException in Java.

    See also:


    Unrelated to the concrete problem, there are 2 other problems with this composite:

    1. The backing component doesn't return the required component family of UINamingContainer.COMPONENT_FAMILY. You can fix it by extending from UINamingContainer instead of UIInput, or by overriding the getFamily() method to return UINamingContainer.COMPONENT_FAMILY.

    2. This is not the right purpose of a composite component. There's no single model value at all. I.e. you don't have a <my:searchUser value="..."> analogous with existing standard components. Rather use an include or tagfile. See also When to use <ui:include>, tag files, composite components and/or custom components? Otherwise, rework the composite as such that you can ultimately use <my:searchUser value="#{bean.foundUser}">.