Search code examples
javascriptjsfjsf-2elrendered-attribute

How to render a h:panelGroup inside ui:repeat based on value from javascript?


I get the boolean value into the <h:inputText> but I can't find a way to get it into the rendered-attribute of the <h:panelGroup>. I also don't see a way to use a bean value, because every iteration would need one on it's own.

this is my jsf code:

<ui:repeat var="item" value="#{itemBean.items}" id="iterateItems" varStatus="iteration">
    <script type="text/javascript">         
        showItem("#{item.id}","#{iteration.index}");
    </script>
    <h:inputText id="rendered"/>
    <h:panelGroup layout="block" rendered="???">
        Iteration #{iteration.index} rendered
    </h:panelGroup>
</ui:repeat>

this is my javascript:

function showItem(item,iteration){
    if((clientSideValue==something){
        document.getElementById("iterateItems"+":"+iteration+":"+"rendered").value = true;
    }
    else{
        document.getElementById("iterateItems"+":"+iteration+":"+"rendered").value = false;
    }
}

Solution

  • JavaScript runs in client side and works on the HTML DOM tree which is retrieved from the server side (and is in your particular case produced by JSF). JavaScript thus expects that the desired HTML element which you'd like to show/hide is always present in the HTML DOM tree.

    JSF runs in server side and produces HTML code based on the JSF component tree (the "view"). When the rendered attribute of a JSF component evaluates to false, no HTML code would be produced for the given component and thus nothing would end up in the HTML DOM tree and thus nothing would be available to be selected by JavaScript's document.getElementById().

    Your concrete functional requirement for which you thought that this would be the solution is unclear, so it's hard to propose the right solution for your concrete problem. But provided that you're absolutely positive that the show/hide needs to be performed in the client side (by JavaScript) instead of the server side (by JSF), then you should be using CSS' display property for this which you can toggle between block and none.

    Here's a basic kickoff example, assuming that you want to initially hide it:

    <ui:repeat var="item" value="#{itemBean.items}" id="iterateItems" varStatus="iteration">
        <script type="text/javascript">         
            showItem(#{iteration.index});
        </script>
        <h:inputText id="rendered" />
        <div id="foo#{iteration.index}" style="display:none">
            Iteration #{iteration.index} shown
        </div>
    </ui:repeat>
    

    with

    function showItem(index) {
        var div = document.getElementById("foo" + index);
    
        if (someCondition) {
            div.style.display = "block"; // Show it.
        } else {
            div.style.display = "none"; // Hide it.
        }
    }