Search code examples
ajaxjsfprimefacesselectonemenuprimefaces-mobile

Primefaces Mobile ajax update of selectOneMenu fails


I want to create a mobile form using Primefaces 5.2 where one selectOneMenu result updates a second selectOneMenu via Ajax, exactly like the showcase example here: http://www.primefaces.org/showcase/ui/ajax/dropdown.xhtml but then a mobile version.

My question is very similar to this one: Primefaces Mobile's Ajax does not update a <p:selectOneMenu> but there is no answer.

I have created a JSF page and backingbean exactly like the showcase example, and it works.

However when I add the mobile aspect using <f:view renderKitId="PRIMEFACES_MOBILE" /> the second selectOneMenu is rendered plain after the update, and a perpetual spinner is displayed.

...
<f:view renderKitId="PRIMEFACES_MOBILE" />
...
<h:body>
<h:form>
    <p:growl id="msgs" showDetail="true" />

    <p:panel header="Select a Location" style="margin-bottom:10px;">
        <h:panelGrid columns="2" cellpadding="5">
            <p:outputLabel for="country" value="Country: " />
            <p:selectOneMenu id="country" value="#{dropdownView.country}" style="width:150px">
                <p:ajax listener="#{dropdownView.onCountryChange}" update="city" />
                <f:selectItem itemLabel="Select Country" itemValue="" noSelectionOption="true" />
                <f:selectItems value="#{dropdownView.countries}" />
            </p:selectOneMenu>

            <p:outputLabel for="city" value="City: " />
            <p:selectOneMenu id="city" value="#{dropdownView.city}" style="width:150px">
                <f:selectItem itemLabel="Select City" itemValue="" noSelectionOption="true" />
                <f:selectItems value="#{dropdownView.cities}" />
            </p:selectOneMenu>

            <p:outputLabel for="debug" value="Debug: " />
            <p:inputText id="debug" value="#{dropdownView.debug}"/>
        </h:panelGrid>
...

The Ajax call works, when my update target is debug my inputText is updated, but when my update target is city the selectOneMenu is not.

Is this a bug? Am I misusing the Mobile aspect? Documentation seems scarce on this.

EDIT

The inputText was not included in the source, corrected.


Solution

  • This is a bug in the JavaScript associated with PrimeFaces mobile. It didn't take into account that the mobile renderer inserts additional JS to afterwards relocate the HTML representation of the dropdown elsewhere in the DOM (evidence can be found by checking the difference between raw HTML output ("View Source" in browser) and the actual HTML DOM tree ("Inspect Element" in browser).

    The exact JavaScript error as shown in Chrome's console is as below:

    Uncaught NotFoundError: Failed to execute 'replaceChild' on 'Node': The node to be replaced is not a child of this node.

    (I hope you'll take it as a learning hint to always check the browser's console for clues)

    Your best bet is to report this as bug to PrimeFaces guys.

    In the meanwhile, the workaround is to wrap it in another (plain) element and update it instead.

    <p:selectOneMenu ...>
        ...
        <p:ajax ... update="cityWrapper" />
    </p:selectOneMenu>
    
    <h:panelGroup id="cityWrapper">
        <p:selectOneMenu id="city" ...>
            ...
        </p:selectOneMenu>
    </h:panelGroup>
    

    Unrelated to the concrete problem: that noSelectionOption="true" has only effect when you add hideNoSelectionOption="true" to the component. See also a.o. Best way to add a "nothing selected" option to a selectOneMenu in JSF. Otherwise, just leave out it.