Search code examples
ajaxjsfcomposite-component

After adding second composite component Error <f:ajax> contains an unknown id


I try to use composite components in my application. When i have added first component it has worked, but when i have added component once again, i have gotten error:

"javax.servlet.ServletException: contains an unknown id 'j_idt202:kladrRegion-dctKladrRegion' - cannot locate it in the context of the component searchButton"

This is code of implementation:

<cc:interface>
    <!-- properties -->
    <cc:attribute name="isDisabled" type="java.lang.Boolean" /> 
    <cc:attribute name="freeForm" type="java.lang.String" /> 
    <cc:attribute name="houseNum" type="java.lang.String" />
    <cc:attribute name="korpusNum" type="java.lang.String" />
    <cc:attribute name="flatNum" type="java.lang.String" />

    <cc:attribute name="kladrRegion" type="java.lang.String" />
    <cc:attribute name="cbKladrRegion" type="javax.faces.component.html.HtmlSelectOneMenu" />
    <cc:attribute name="kladrRegions" type="java.util.List" />

    <cc:attribute name="kladrCity" type="java.lang.String" />
    <cc:attribute name="cbKladrCity" type="javax.faces.component.html.HtmlSelectOneMenu" />
    <cc:attribute name="kladrCities" type="java.util.List" />

    <cc:attribute name="kladrSearch" type="java.lang.String" />
    <cc:attribute name="cbKladrSearch" type="org.icefaces.ace.component.combobox.ComboBox" />
    <cc:attribute name="kladrSearches" type="java.util.List" />

    <!-- methods -->
    <cc:attribute name="listener" 
                  method-signature="void actionListener(javax.faces.event.AjaxBehaviorEvent)"/>
    <cc:attribute name="kladrRegionChange" 
                  method-signature="void actionListener(javax.faces.event.AjaxBehaviorEvent)"/>
    <cc:attribute name="kladrCityChange" 
                  method-signature="void actionListener(javax.faces.event.AjaxBehaviorEvent)"/>
    <cc:attribute name="kladrDlgCloseClick" 
                  method-signature="void actionListener(javax.faces.event.AjaxBehaviorEvent)"/>
    <cc:attribute name="kladrDlgSaveClick" 
                  method-signature="void actionListener(javax.faces.event.AjaxBehaviorEvent)"/>
    <cc:attribute name="searchKladrAction" 
                  method-signature="java.lang.String action(java.lang.String)"/>
</cc:interface>

<cc:implementation>
    <h:panelGrid styleClass="panelGrid" columns="2">
        <h:panelGroup styleClass="panelGroup">
            <div class="searchWrap">
                <h:commandLink id="searchButton"
                               disabled="#{cc.attrs.isDisabled}"
                               onclick="openKladrDialog(this, '#{cc.clientId}')">
                    <h:graphicImage value="/resources/images/search.png" 
                                    alt="#{usertag.labelSearchAddr}" />
                    <f:ajax event="click" 
                            render="kladrRegion-dctKladrRegion"
                            listener="#{cc.attrs.listener}"/>
                </h:commandLink>
            </div>
        </h:panelGroup>

        ...etc.

    </h:panelGrid>

    <!-- dialog -->
    <div id="#{cc.clientId}_kladrDialog">
        <h:panelGrid styleClass="panelGrid" columns="3">            
            <h:outputLabel value="Country" class="outputLabel" for="kladrCountry" />
            <h:panelGroup styleClass="panelGroup"> 
                <ice:inputText disabled="true" value="Russia" 
                               styleClass="ui-inputfield ui-corner-all inputText kladrSearchFormInput kladrSearchFormInputWidth" />    
                <h:inputHidden id="kladrCountry" value="179" />
            </h:panelGroup>
            <h:outputLabel />

            <h:outputLabel value="Region" class="outputLabel" />
            <h:selectOneMenu id="kladrRegion-dctKladrRegion" 
                             value="#{cc.attrs.kladrRegion}" >
                <f:selectItems value="#{cc.attrs.kladrRegions}" var="region" 
                               itemLabel="#{region.value}" itemValue="#{region.id}" />                                
                <f:ajax render="@this kladrCity-dctKladrCity" 
                        listener="#{cc.attrs.kladrRegionChange}" />
            </h:selectOneMenu>

            ... etc.
    </div>

</cc:implementation>

This is code of tag:

<kladr:usertag  isDisabled="#{PolicyBean.policyDisabled}"
                freeForm="#{PolicyBean.policyAuto.holder.baseAddress.freeForm}"
                houseNum="#{PolicyBean.policyAuto.holder.baseAddress.houseNum}"
                korpusNum="#{PolicyBean.policyAuto.holder.baseAddress.korpusNum}"
                flatNum="#{PolicyBean.policyAuto.holder.baseAddress.flatNum}"

                kladrRegion="#{PolicyBean.kladrRegion}"
                cbKladrRegion="#{PolicyBean.cbKladrRegion}"
                kladrRegions="#{PolicyBean.kladrRegions}"

                kladrCity="#{PolicyBean.kladrCity}"
                cbKladrCity="#{PolicyBean.cbKladrCity}"
                kladrCities="#{PolicyBean.kladrCities}"

                kladrSearch="#{PolicyBean.kladrSearch}"
                cbKladrSearch="#{PolicyBean.cbKladrSearch}"
                kladrSearches="#{PolicyBean.kladrSearches}"

                listener="#{PolicyBean.holderKladrDlgOpenClick}"
                kladrRegionChange="#{PolicyBean.kladrRegionChange}"
                kladrCityChange="#{PolicyBean.kladrCityChange}"
                kladrDlgCloseClick="#{PolicyBean.kladrDlgCloseClick}"
                kladrDlgSaveClick="#{PolicyBean.kladrDlgSaveClick}"
                searchKladrAction="#{PolicyBean.kladrSearchClick(PolicyBean.kladrSearch)}" />

any ideas?


Solution

  • The problem is, that your <h:selectOneMenu id="kladrRegion-dctKladrRegion"> is in another parent component than your <h:commandLink id="searchButton" ....

    It will work correctly, if you specify the correct absolute component id (or move your dialog inside the same parent).

    See Find component by ID in JSF on how to find the correct component id.

    The exception tells you that there is not component with id "kladrRegion-dctKladrRegion" inside the component <h:panelGroup> whid got the generated id "j_idt202".

    If you're using PrimeFaces, you can use the EL Function component('id') which returns the correct component id. See http://www.primefaces.org/docs/guide/primefaces_user_guide_5_1.pdf, chapter 11.2.