views:

404

answers:

3

Hi all, I have a question regarding the placement of javascript within facelet components. This is more regarding best practice/style than a programming issue, but I feel like all the solutions I have thought of have been hacks at best. Ok here is my scenario:

I have a facelet template like so (my faces, and apache Trinidad)...

<ui:composition>
<f:view locale="#{myLocale}">
    <ui:insert name="messageBundles" /><!--Here we add load bundle tags-->

    <tr:document mode="strict" styleClass="coolStyleDoc">

        <f:facet name="metaContainer">
            <!--This trinidad defined facet is added to HTML head-->
            <tr:group> <!-- blah bal my own styles and js common to all  -->
                <ui:insert name="metaData" />
            </tr:group>
        </f:facet>
        <tr:form usesUpload="#{empty usesUpload ? 'false' : usesUpload}">
            <div id="formTemplateHeader">
                <ui:insert name="contentHeader" />
            </div>
            <div id="formTemplateContentContainer">
                <div id="formTemplateContent">
                    <ui:insert name="contentBody" />
                </div>
            </div>
            <div id="formTemplateFooter">
                <ui:insert name="contentFooter">
                </ui:insert>
            </div>
        </tr:form>
<!-- etc...--->

Now, a facelet that wants to use this template would look like the following:

<ui:composition template="/path/to/my/template.jspx">

    <ui:define name="bundles">
        <custom:loadBundle basename="messagesStuff" var="bundle" />
    </ui:define>

    <ui:define name="metaData">
        <script>
        <!-- cool javascript stuff goes here-->
        </script>
    </ui:define>

    <ui:define name="contentHeader">
        <!-- MY HEADING!-->
    </ui:define>

    <ui:define name="contentBody">
        <!-- MY Body!-->
    </ui:define>

    <ui:define name="contentFooter">
        <!-- Copyright/footer stuff!-->
    </ui:define>
</ui:composition>

All this works quite well, but the problem I have is when I want to use a facelet component inside this page. If the facelet component has its own javascript code (jQuery stuff etc), how can I make it so that that javascript code is included in the header section of the generated html? Any help would be appreciated. Please let me know if this is not clear or something... thanks in advance

A: 

You can include the script by either:

  • <script type="text/javascript" src="externalScript.js"></script>
  • or

    <script type="text/javascript">
    //<![CDATA[
    ....
    //]]>
    <//script>
    
Bozho
Well, maybe I was unclear, but I know I can embed js in the facelet, but a re-usable facelet component is usually a fragment, i.e. it does not contain 100% proper html. In my case, I am embedding a facelet into a page that uses the template. The embedded facelet may only define <table>...</table> for instance. So how could I add javascript in the embedded facelet page that would get rendered in the <head> tag of the main HTML output. Is that clearer?
Java Drinker
Well, just put it in the template with `<ui:insert>` and then define it with `<ui:define>` ?
Bozho
+2  A: 

Assuming JSF2 Facelets, you should be able to do something with the h:head/h:outputScript tags.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
           "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"&gt;
    <h:head>
        <title>JSF2</title>
    </h:head>
    <h:body>
        Hello from Facelets
        <h:outputScript target="head">
        <![CDATA[
          document.write("<!-- this will render in the head tag -->");
        ]]>
        </h:outputScript>
    </h:body>
</html>
McDowell
Damn, I wish I were using jsf 2.0. All kinds of good stuff like annotations and this solution you posted! Alas, stuck with the old version for now (1.1!!). Perhaps there is a way to simulate this behavior using a custom component that modifies the component tree? Hmmm, I could look into that, although a little bit out of my comfort level with this stuff. Thanks for the response... I don't have enough exp to upvote just yet
Java Drinker
+1  A: 

Hey everyone, just in case anyone was also wondering, and stuck like me with the old jsf, or couldn't use the method proposed by McDowell for some reason, here is how i ended up doing it. It's sort of a lazy man's way, enforced only by convention, not code.

So here is my page that uses the template for it's layout. You can see that it embeds the customFacelet component twice.

<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:tr="http://myfaces.apache.org/trinidad"
xmlns:custom="http://mycompany.com/jsf/custom"&gt;

<ui:composition template="/path/to/template.jspx">

    <ui:define name="bundles">
        <custom:loadBundle basename="bundleName" var="msgs" />
    </ui:define>

    <ui:define name="metaData">
      <!-- Custom facelet javascript part only -->
        <custom:faceletComponent type="metaData" />
    </ui:define>

    <ui:define name="contentHeader">
        <!-- Fixed header stuff -->
    </ui:define>

    <ui:define name="contentBody">
      <!-- Lots of tables and graphs and awesome content first .... -->

      <!-- Custom facelet again, this time with content only  -->
        <custom:faceletComponent type="content" data="#{bean.data}"/>
    </ui:define>

    <ui:define name="contentFooter">
        <!-- Fixed footer stuff -->
    </ui:define>

</ui:composition>

And here is the facelet, that defines separately rendered areas for js and content...

<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>

<!-- This facelet requires the metaData sections to be placed in the header

    Required Attributes:

    NAME            TYPE                        DESCRIPTION
    =====           =====                       ============
    type            String                  One of ['metaData', 'content']. Determines which section to render
    data      MyBeanType      Get all the facelet data              

-->
<ui:composition>

    <tr:group rendered="#{type eq 'metaData'}">
      <!-- All of this should go in the header-->
        <script type="text/javascript">
            Event.observe(document, 'dom:loaded', function(e) {
      //Funky jQuery stuff here that does tranitions and animations etc
    });
        </script>
    </tr:group>

    <tr:group rendered="#{type eq 'content'}">
      <!-- Here is the facelet content, shared widget html etc
    This part relies on the javascript above
  -->
    </tr:group>
</ui:composition>

Java Drinker