Search code examples
jsfjsf-2managed-bean

JSF - how to add child to h:head or to h:body with managed bean


I am trying to test my managed bean to modify web page dynamically (programmatically); Most of jsf examples show how to use binding to modify ui but what about the rest of the web page? The samples are showing how to get to the UIViewRoot which is usually located in h:body block but what about the h:body itself or the h:head?

So my question is... Is there a way using FacesContext to get h:body or h:head as parent components and add children to them right with managed bean or please advise of how to get alike effect using other ways?

Thanks


Solution

  • UIViewRoot is represented by <f:view> tag. If you don't define it explicitly in your JSF page, then it is added implicitly.

    UIViewRoot which is usually located in h:body block

    No, it is not inside the body, but by default surrounding the body and head. Like this:

    <html xmlns="http://www.w3.org/1999/xhtml"  
        xmlns:h="http://java.sun.com/jsf/html"  
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:ui="http://java.sun.com/jsf/facelets"> 
        <f:view> <!-- No need to define. Added implicitly here in ComponentTree -->
            <h:head>
                <meta http-equiv="content-type" content="text/html;charset=UTF-8"/>
            </h:head> 
            <h:body>    
                <h:outputText value="#{hello.message}"/>            
           </h:body>
       </f:view>
    </html> 
    

    So if you obtain the UIViewRoot using FacesContext.getCurrentInstance().getViewRoot() and ask for its children (.getChildren()), you will get a list of 4 elements:

    1. UIInstructions: renders <html>opening tag
    2. UIOutput: this is the <h:head>. Ask for getChildren again to obtain a UIOutput for the <meta> tag
    3. HtmlBody: this is h:body apparently. Ask for getChildren to get <h:outputText>
    4. UIInstructions: renders the </html> closing tag

    add children to them right with managed bean

    Yes, in general you can use your ManagedBeans to manipulate the UIComponentTree (e.g. add item, then reload the page to show it). However, consider the JSF lifecycle and processing order (you e.g. cannot add a child as first element to the body during render-phase, cause items were already processed). Sample to add new element to body:

    List<UIComponent> viewRootChildren = FacesContext.getCurrentInstance().getViewRoot().getChildren();
    for(UIComponent child : viewRootChildren){
        if( child instanceof HtmlBody ){
            HtmlOutputText newText = new HtmlOutputText();
            newText.setValue("added dynamically");
            child.add(newText);
        }
    }