Search code examples
javascriptjsffacelets

JSF components not parsed inside a <script> block


I had to change a <script> ... </script> in an JSF page and tried to evaluate a JSF component inside of the script. The EL was evaluated but the tag itself was untouched.

What is the reason for this behaviour?

Example:

<script type="text/javascript">
    //<![CDATA[
        function doSomething() {
            $('.userNode').droppable({
                activeClass : 'ui-state-active',
                hoverClass : 'ui-state-highlight',
                tolerance : 'intersect',
                drop : function(event, ui) {
                   <h:panelGroup rendered="#{myBean.useThis}">
                     alert("code A");
                   </h:panelGroup>
                   <h:panelGroup rendered="#{!myBean.useThis}">
                     alert("code B");
                   </h:panelGroup>
        }
            });
        };
    //]]>   </script>

The EL #{!myBean.useThis} was evaluated to true/false but the <h:panelGroup> was in the result of the rendering.

Why?


Solution

  • It's because you placed it inside a CDATA block. Anything inside a CDATA block is considered character data, not as XML data.

    Better don't do this at all. This is a poor practice. Put the JS function in its own .js file. Use JSF/EL only to prepare JavaScript variables which the JS functions will then ask for (as method argument) or access by itself (in window scope), not to fill parts of JS functions.

    E.g.

    <h:outputScript>var useThis = #{myBean.useThis};</h:outputScript>
    <h:outputScript name="script.js" />
    
    function doSomething() {
        $('.userNode').droppable({
            activeClass : 'ui-state-active',
            hoverClass : 'ui-state-highlight',
            tolerance : 'intersect',
            drop : function(event, ui) {
               if (useThis) {
                   alert("code A");
               }
               else {
                   alert("code B");
               }
            }
        });
    }
    

    To prevent pollution of global scope, consider creating a namespace.

    <h:outputScript>var my = my||{}; my.useThis = #{myBean.useThis};</h:outputScript>
    
               if (my.useThis) {
                   alert("code A");
               }
               else {
                   alert("code B");
               }
    

    See also: