Using composite:insertFacet/renderFacet does not work inside t:dataTable

别说谁变了你拦得住时间么 提交于 2019-12-31 00:44:53

问题


I'm doing this: resources/vm/table.xhtml:

...
<composite:interface>
  <composite:facet name="dataBody" required="true"/>
</composite:interface>
...
<composite:implementation>
  <t:dataTable>
    <composite:renderFacet name="dataBody"/>
  </t:dataTable>
</composite:implementation>
...

And in page.xhtml:

...
<vm:table>
  <f:facet name="dataBody">
    <t:column>
      Testing.
    </t:column>
  </f:facet name="dataBody">
</vm:table>
...

Problem: The 'dataBody' facet is not rendered. In JSF1.2 I used to do this with ui:insert and that worked fine.

Question: Why doesn't it work and how should I use the template as an alternative?

Also see: http://lists.jboss.org/pipermail/jsr-314-open-mirror/2009-September/001526.html


回答1:


SOLVED: I had to use insertChildren and then everything works :) Took me 1.5 days to find this... Now looks so simple. Migrating from RichFaces3.3.3/JSF1.2 to RichFaces4.0/JSF2 is a lot of work and a lot to learn. But I'm getting there :)

resources/vm/table.xhtml:

...
<composite:interface>
</composite:interface>
...
<composite:implementation>
  <t:dataTable>
    <composite:insertChildren/>
  </t:dataTable>
</composite:implementation>
...

And in page.xhtml:

...
<vm:table>
  <t:column>
    Testing.
  </t:column>
</vm:table>
...



回答2:


Here is the implentation of <cc:insertRawFacet> tag by myself, it works just like the ui:insert. Well, this is a MyFaces solution, though.

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import javax.faces.component.UIComponent;
import javax.faces.view.facelets.FaceletContext;
import javax.faces.view.facelets.FaceletHandler;
import javax.faces.view.facelets.FacetHandler;
import javax.faces.view.facelets.TagConfig;
import javax.faces.view.facelets.TagHandler;
import javax.free.UnexpectedException;

import org.apache.myfaces.view.facelets.AbstractFaceletContext;
import org.apache.myfaces.view.facelets.TemplateClient;
import org.apache.myfaces.view.facelets.TemplateContext;
import org.apache.myfaces.view.facelets.TemplateManager;
import org.apache.myfaces.view.facelets.tag.composite.CompositeComponentResourceTagHandler;
import org.apache.myfaces.view.facelets.tag.composite.InsertFacetHandler;

public class InsertRawFacetHandler
        extends InsertFacetHandler {

    static final Logger logger = Logger.getLogger(InsertRawFacetHandler.class.getName());

    public InsertRawFacetHandler(TagConfig config) {
        super(config);
    }

    @Override
    public String getFacetName(FaceletContext ctx) {
        return _name.getValue(ctx);
    }

    @Override
    public void apply(FaceletContext ctx, UIComponent parent)
            throws IOException {
        String facetName = _name.getValue(ctx);

        AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
        // actx.includeCompositeComponentDefinition(parent, facetName);
        TemplateClient ccClient;
        TemplateContext tctx = actx.popTemplateContext();
        try {
            ccClient = tctx.getCompositeComponentClient();
        } finally {
            actx.pushTemplateContext(tctx);
        }

        while (ccClient instanceof TemplateManager) {
            ccClient = getProtectedTarget(ccClient);
        }
        if (ccClient == null)
            throw new NullPointerException("No cc client.");

        // Instead of ccClient.apply(actx, parent, facetName), we'll drop the enclosing <f:facet>
        if (!(ccClient instanceof CompositeComponentResourceTagHandler))
            throw new RuntimeException("ccClient isn't a resource tag handler.");

        CompositeComponentResourceTagHandler ccClientHandler = (CompositeComponentResourceTagHandler) ccClient;
        TagHandler facetHandler = getFacetHandler(ctx, ccClientHandler, facetName);
        if (facetHandler != null) {
            TemplateContext itc = actx.popTemplateContext();
            try {
                // facetHandler.apply(ctx, parent);
                FaceletHandler facetNextHandler = getNextHandler(facetHandler);
                facetNextHandler.apply(ctx, parent);
            } finally {
                actx.pushTemplateContext(itc);
            }
        }
    }

    static TemplateClient getProtectedTarget(TemplateClient client) {
        Field _targetField;
        try {
            _targetField = client.getClass().getDeclaredField("_target");
        } catch (NoSuchFieldException e) {
            return null;
        }
        _targetField.setAccessible(true);
        try {
            return (TemplateClient) _targetField.get(client);
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    static final Field _facetHandlersMapField;
    static final Field _facetHandlersField;
    static {
        try {
            _facetHandlersMapField = CompositeComponentResourceTagHandler.class.getDeclaredField("_facetHandlersMap");
            _facetHandlersField = CompositeComponentResourceTagHandler.class.getDeclaredField("_facetHandlers");
            _facetHandlersMapField.setAccessible(true);
            _facetHandlersField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            throw new UnexpectedException(e);
        }
    }

    static TagHandler getFacetHandler(FaceletContext ctx, CompositeComponentResourceTagHandler client, String facetName) {
        try {
            Map<String, TagHandler> _facetHandlersMap = (Map<String, TagHandler>) _facetHandlersMapField.get(client);
            if (_facetHandlersMap == null) {
                Map<String, TagHandler> map = new HashMap<String, TagHandler>();

                Collection<FaceletHandler> _facetHandlers = (Collection<FaceletHandler>) _facetHandlersField
                        .get(client);
                if (_facetHandlers != null) {
                    for (FaceletHandler handler : _facetHandlers) {
                        if (!(handler instanceof TagHandler))
                            throw new UnexpectedException("Facet-handler is not a tag-handler: " + handler);

                        String name = null;
                        if (handler instanceof FacetHandler)
                            name = ((FacetHandler) handler).getFacetName(ctx);
                        else if (handler instanceof InsertFacetHandler)
                            name = ((InsertFacetHandler) handler).getFacetName(ctx);
                        else
                            throw new UnexpectedException("Unknown facet type.");

                        map.put(name, (TagHandler) handler);
                    }
                }

                _facetHandlersMap = map;
                _facetHandlersMapField.set(client, _facetHandlersMap);
            }
            return _facetHandlersMap.get(facetName);
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e);
        }
    }

    static final Field nextHandlerField;
    static {
        try {
            nextHandlerField = TagHandler.class.getDeclaredField("nextHandler");
            nextHandlerField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            throw new UnexpectedException(e);
        }
    }

    static FaceletHandler getNextHandler(TagHandler handler) {
        try {
            return (FaceletHandler) nextHandlerField.get(handler);
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

}

Design composite component as a black box, and retarget the facet components, this may sound great, but it won't work, results in duplicated id(s), and other problems.

You can replace cc:renderFacet by this renderRawFacet, the difference is, if you have naming container in the composite component, the container client ids will prepended to the facet definition components.

See:

  1. Discussion on insert/renderFacet.
  2. JSF-2.2 won't include improvement on this issue.
  3. How to write your own tag handler.

Tested under Myfaces-2.1.1.



来源:https://stackoverflow.com/questions/7891650/using-compositeinsertfacet-renderfacet-does-not-work-inside-tdatatable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!