Hi,

This is not a MyFaces issue, but i've been advised to post here since
i'm more likely to find people interested and knowledgeable in
facelets interaction with ajax.

Facelets is an amazing product, and I've been very pleased to use it
to develop a layout system, generating forms to present documents
metadata in different modes (create, edit, view...), and it works very
well, except when performing some kinds of ajax re-rendering.

I'm using facelet tag handlers that will dynamically build the
subsequent handlers to use from an external XML configuration. When
doing so, i'm exposing some variables to the EL context (via the
variable mapper) so that i can use these variables in xhtml templates
referenced in the XML config. These variables resolve to objects that
are only available in the context of my tag handler.

My problem is that the default ComponentHandler class "caches"
components (see ComponentSupport#findChildByTagId): it will not
re-create the component if it is already found in the view, and this
is what is happening when doing ajax re-rendering. The component is
displayed, but as its properties have not been re-created, they hold
references to the old variables that the tag handler previously
exposed in the context.

The main classes and template performing the rendering are here:
http://hg.nuxeo.org/nuxeo/nuxeo-jsf/file/5.4/nuxeo-platform-forms-layout-client/src/main/java/org/nuxeo/ecm/platform/forms/layout/facelets/LayoutTagHandler.java
http://hg.nuxeo.org/nuxeo/nuxeo-jsf/file/5.4/nuxeo-platform-forms-layout-client/src/main/java/org/nuxeo/ecm/platform/forms/layout/facelets/LayoutRowTagHandler.java
http://hg.nuxeo.org/nuxeo/nuxeo-jsf/file/5.4/nuxeo-platform-forms-layout-client/src/main/java/org/nuxeo/ecm/platform/forms/layout/facelets/LayoutRowWidgetTagHandler.java
http://hg.nuxeo.org/nuxeo/nuxeo-jsf/file/5.4/nuxeo-platform-webapp-base/src/main/resources/nuxeo.war/layouts/layout_default_template.xhtml

For instance the LayoutTagHandler class uses a xhtml template (see
above) that contains the tag <h:outputText value="#{widget.label}" />.
The "widget" variable is exposed in the context by the
LayoutRowWidgetTagHandler class. The UIOutput component is not being
re-created, so it holds references to the old "widget" value exposed
in the variable mapper. On the other hand, displaying #{widget.label}
without the UIOutput component will work as expected.

I've been trying to "hack" the detection of pre-existing components by
computing custom identifiers in TagConfig instances used by my tag
handlers, but this is not enough for JSF tags present in the layout
template as above, as i'm letting the default facelets system handle
them (via ctx.includeFacelet(parent, template)).

So I would be interested if anyone had some suggestions or ran into
the same problem and found a good solution. Do I need to re-define the
generic ComponentHandler so that it does not perform caching in my use
cases (I'd rather not)? Do i need to make variables available in the
context differently?...

Please do not hesitate to tell if you'd rather have a minimal example
on how to reproduce my problem: i'd be happy to provide it. If it
makes a difference, i'm currently using version 1.1.11 of facelets,
and will be migrating to version 1.1.15 very shortly (and using
version 1.2_09 of sun jsf library).

Thanks a lot in advance!
anahide.

PS: if some people are interested, documentation of the feature is
here: http://doc.nuxeo.com/display/NXDOC/Layouts

Reply via email to