Search code examples
ajaxjsfuicomponents

JSF: When to add ClientBehavior to own component


I am developing a component containing an AJAX client behavior. The behavior depends on the parameters provided to the component (e.g. render and execute targets). Due to performance reasons I do not want to realize the component using facelet based composite components.

My question is, when the client behavior shall be added to the component. If I call addClientBehavior() in the encodeBegin() method, I receive a NullPointerException in UIComponentBase.restoreBehaviorsState(). If I add the behavior at construction time, the ajax request works, however the parameters are not yet available. Is there a suitable method or event when to properly add the behavior?

I use mojarra 2.1.7. Below is a short example of my component without the dynamic ajax stuff:

@FacesComponent(value="simpleTestLink")
public class SimpleTestLink extends HtmlCommandLink{


    private Logger logger=LoggerFactory.getLogger(getClass());
    private AjaxBehavior ajax;

    enum PropertyKeys{aProp};

    public SimpleTestLink() {
        logger.debug("SimpleTestLink created");
        // adding ajax here works, but no parameters available yet
        ajax = new AjaxBehavior();
        ajax.setExecute(Arrays.asList(new String[]{"@this"}));
        ajax.setRender(Arrays.asList(new String[]{"@form"}));
        addClientBehavior(getDefaultEventName(), ajax);

    }

    @Override
    public void encodeBegin(FacesContext context) throws IOException {
        logger.debug("encodeBegin num: " + getAttr());
        // adding ajax here fails
        super.encodeBegin(context);
    }

    @Override
    public boolean getRendersChildren() {
        return true;
    }

    @Override
    public void encodeChildren(FacesContext context) throws IOException {
        Object attr = getAttr();
        HtmlOutputText outputText = new HtmlOutputText();
        outputText.setValue("testlink["+ attr+"]\n");
        outputText.encodeAll(context);
        super.encodeChildren(context);
    }

    private Object getAttr() {
        return getAttributes().get(PropertyKeys.aProp.name());
    }

}

Thanks for any help,
Jens


Solution

  • Yes, the 'suitable method or event' is called PreRenderViewEvent. I've blogged how to use it here: http://blog.kennardconsulting.com/2010/10/safely-manipulating-component-tree-with.html