jsfomnifaces

Omnifaces TagAttribute Id cannot be used as id


I have the following Facelet Taglib:

<ui:composition
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
        xmlns:o="http://omnifaces.org/ui"
        xmlns:h="http://java.sun.com/jsf/html">

    <o:tagAttribute name="id"/>

    <h:panelGroup id="#{id}" layout="block" styleClass="idTest">
        #{id}
    </h:panelGroup>
</ui:composition>

The taglib.xml looks like this:

<tag>
    <tag-name>idTest</tag-name>
    <source>resources/myProject/tags/idTest.xhtml</source>
</tag>

And the code, where it is used is simply:

<myProject:idTest/>

How can it be, that the following HTML is being rendered:

<div class="idTest">
    j_ido489794984_4bf870cd
</div>

Why does my PanelGroup have no id? The id is generated like it is expected based on the documentation of o:tagAttribute, since the content of the div is rendered. But as id it does not work. Why?


Solution

  • This is indeed confusing.

    The documentation literally says:

    ... it will autogenerate an unique ID in the form of j_ido[tagId] where [tagId] is the <o:tagAttribute> tag's own unique ID.

    But the actual behavior is more like so:

    ... it will override any autogenerated ID into the form of j_ido[tagId] where [tagId] is the <o:tagAttribute> tag's own unique ID.

    In other words, when JSF itself needs to render the id attribute of a HTML element, usually because it's required by some internal logic further down in the chain, such as <f:ajax> and friends, and there is no explicit ID specified on the tag like so <x:someTag id="fixedId" />, then JSF will by default autogenerate one in the form of j_id[autoIncrementInteger]. But this will go wrong on tagfiles because the autoIncrementInteger may get bumped further by one on each postback depending on the JSF impl and view state configuration used. The <o:tagAttribute> simply attempts to ensure this way that the autogenerated ID stays the same on each postback.

    When you edit your test tagfile to add <f:ajax>,

    <h:panelGroup id="#{id}" layout="block" styleClass="idTest">
        <f:ajax event="click" />
    </h:panelGroup>
    

    then you'll see that the generated <div> has an id, because this is technically required by <f:ajax>.

    <div id="j_ido-1512689859_13a7e7e3" class="idTest"
        onclick="mojarra.ab(this,event,'click',0,0)">
    </div>
    

    Or when you swap <h:panelGroup> for e.g. a <h:form> or whatever component which always requires an ID in the client side,

    <h:form id="#{id}" styleClass="idTest">
        <ui:insert />
    </h:form>
    

    then you'll also see that it's generated.

    <form id="j_ido-1512689859_13a7e7e3" name="j_ido-1512689859_13a7e7e3" method="post" action="/test.xhtml" class="idTest" enctype="application/x-www-form-urlencoded">
        <input type="hidden" name="j_ido-1512689859_13a7e7e3" value="j_ido-1512689859_13a7e7e3" />
        ...
    </form>
    

    In other words, the feature is working fine, but it was simply not used in your specific case because JSF didn't consider it necessary to generate it.

    I've in the meanwhile updated the documentation.