Christian Voß
Christian Voß

Reputation: 61

Custom Component: how to populate an ELContext Variable to rendered children

i'm trying to get a better grasp of JSF2 internals by writing a small "tree" component, that takes a node-Structure and renders it into simple ul/li elements.

It should be possible to define the Way, the content of a leaf is rendered somewhat like this (similar to h:DataTable):

<custom:tree value="#{someBean.someListProperty}" var="nodeData">
    <h:outputText value="#{nodeData}" />
    ...
</custom:tree>

Currently i'm struggling to figure out, how to "populate" that variable into the current context. I tried something like this, but it didn't work:

@Override
@SuppressWarnings("unchecked")
public void encodeChildren(FacesContext context) throws IOException {
    if ((context == null)){
        throw new NullPointerException();
    }

    ArrayList<String> list = (ArrayList<String>) getStateHelper().eval("value");
    String varname = (String) getStateHelper().eval("var");
    if(list != null){
        for(String str : list){
            getStateHelper().put(varname, str);
            for(UIComponent child: getChildren()){
                child.encodeAll(context);
            }
        }
    }
}

For simplification i first started to use a simple ArrayList of Strings and print out the contents iteratively. Here is the xhtml:

<custom:tree value="#{testBean.strings}" var="testdata">
    <h:outputText value="#{testdata}" />
</custom:tree>

So, what would be the correct way to achieve this?

Best regards, Christian Voß

Upvotes: 1

Views: 936

Answers (1)

Christian Vo&#223;
Christian Vo&#223;

Reputation: 61

Thanks BalusC,

to keep it simple, this is basically the (or better one possible) answer to my question:

You can put a new variable under the given key into the requestMap and any child component will be able to access it, using the specified ValueExpression.

@Override
@SuppressWarnings("unchecked")
public void encodeChildren(FacesContext context) throws IOException {
    if ((context == null)){
        throw new NullPointerException();
    }

    ArrayList<String> list = (ArrayList<String>) getStateHelper().eval("value");
    String varname = (String) getStateHelper().eval("var");
    Map<String, Object> requestMap = context.getExternalContext().getRequestMap();

    varStore = requestMap.get(varname); // in case this Object already exists in the requestMap,
                                        // emulate "scoped behavior" by storing the value and
                                        // restoring it after all rendering is done.

    if(list != null){
        for(String str : list){
            requestMap.put(varname, str);
            for(UIComponent child: getChildren()){
                child.encodeAll(context);
            }
        }           
        // restore the original value
        if(varStore != null){
            requestMap.put(varname, varStore);
        }else{
            requestMap.remove(varname);
        }
    }
}

Upvotes: 2

Related Questions