JSF 2.0 复合组件 - ajax 渲染参数 OUTSIDE 组件定义

Posted

技术标签:

【中文标题】JSF 2.0 复合组件 - ajax 渲染参数 OUTSIDE 组件定义【英文标题】:JSF 2.0 Composite components - ajax render parameter OUTSIDE component definition 【发布时间】:2011-03-06 05:02:13 【问题描述】:

考虑一个简单的复合组件,它采用某种动作参数 - 例如,一个简单的链接“美化器”。我想“ajaxify”它。

   <composite:interface>
        <composite:attribute name="act" method-signature="java.lang.String action()"></composite:attribute>
        <composite:attribute name="text" required="true"></composite:attribute>
            <composite:clientBehavior  name="click" event="action"  targets="l"/>    </composite:interface>

   <composite:implementation>
        <h:commandLink id="l" act="#cc.attrs.action" immediate="true">            <b>#cc.attrs.text</b>         </h:commandLink>    </composite:implementation>

我通过客户行为公开一个事件。我是这样使用的:

<h:panelGroup layout="block" id="outside">

        #mybean.otherdata <br/>

                <mc:mylink text="Click click" action="#mybean.click" >
                    <f:ajax event="click" render="outside"/>"
                </mc:mylink><br/>

</h:panelGroup>

你可以看到我想做的事情:我想做一个ajax渲染在复合定义之外;只需将渲染设置为“外部”就会出现可怕的&lt;f:ajax&gt; contains an unknown id 错误。

是的,我知道命名容器,而且我知道我们可以在前面加上一个冒号并指定一个绝对路径,但这很笨拙。如果我将它包裹在更多的层中(这是重点),我必须手动将这些引用链接在一起。

我可以进行某种相对引用,例如render="../outside",以跳过对组件父容器的引用吗?

我用 a4j 做了一个 jsf 1 的应用,这个模式到处都在使用。

【问题讨论】:

“这种模式在所有地方都被使用”我的意思是 a4j 似乎会爬上容器层次结构,直到找到匹配项。复合组件 def 似乎在组件边界处终止搜索 【参考方案1】:

cc.parent.cliendId 解析父复合组件而不是直接父组件。 Obtaining the clientId of the parent of a JSF2 composite component

<composite:interface>
    <cc:attribute name="render"  type="java.lang.String"   default="@this"/>
    <cc:attribute name="action"  method-signature="java.lang.String action()">
</composite:interface>

</composite:implementation>
    <h:form>
        <h:commandLink action="#cc.attrs.action" value="Click"> 
            <f:ajax render="cc.attr.render" execute="@form"
        </h:commandLink>
    </h:form>    
</composite:implementation>

所以你可以自行决定要渲染哪个组件。

<h:panelGroup layout="block" id="outside">
    #mybean.otherdata
    <mc:mylink action="#mybean.click" render=":outside"/>
</h:panelGroup>               

【讨论】:

【参考方案2】:

经过一番修改,这里有一个解决方案:

在事件上放置一个监听器:

<f:ajax event="click" listener="#mycomp.listen" render="#mycomp.getParId('outside')"/>"

实施:

public void listen(AjaxBehaviorEvent event) 
    String clid=event.getComponent().getClientId();

    StringTokenizer st=new StringTokenizer(clid,":");

    StringBuilder sb=new StringBuilder(":");
    for (int x=1;x<st.countTokens();x++)
    
        sb.append(st.nextToken()).append(":");
    

    parId=sb.toString();


public String getParId(String suff) 
    //must precheck as id is prevalidated for existence. if not set yet set to form
    if (parId==null)
    
        return "@form";
    
    return parId+suff;

即便如此,你为什么要这样做?

【讨论】:

【参考方案3】:

我找到了一个我很满意的更好的解决方案,它利用了模板中的隐式“组件”映射。它允许使用../ 文件系统表示法从复合组件返回基本的相对映射。它可以扩展以处理更多,但这就是我所需要的。它也适用于执行参数。

感谢我解决这个问题!再说一次,我是不是误会了什么?我应该不需要弄清楚这一点。

用法:

<mc:mylink text="Click me" action="#blah.myaction" render="../../pg" />

实施:

<composite:implementation>

    <h:commandLink id="l" action="#cc.attrs.action" immediate="true">
        <f:ajax render="#pathProcessor.pathProcess(3, cc.attrs.render, component.clientId)" />
                     #simon.rand . <b>#cc.attrs.text</b>
    </h:commandLink>

.....

路径处理器方法:

public static String pathProcess(int currentNesting, String path, String clid) 

    //System.out.println("clientid is "+clid);
    //System.out.println("path is "+path);
    //System.out.println("nesting is "+currentNesting);

    String backTok="../";
    String sepchar=":";

    StringBuilder src=new StringBuilder(path);
    int backs=0;
    int inc=backTok.length();

    while (src.indexOf(backTok,backs*inc)==backs*inc)
    
        backs++;
    

    //get rid of the source
    String suffix=src.substring(backs*inc);

    //add in internal nesting
    backs+=(currentNesting-4);

    StringTokenizer st=new StringTokenizer(clid,sepchar);

    StringBuilder sb=new StringBuilder(sepchar);
    for (int x=0;x<st.countTokens()-backs;x++)
    
        sb.append(st.nextToken()).append(sepchar);
    

    //backtracked path
    String p=sb.toString();

    //add suffix to the backtracked client path to get full absolute path
    String abs=p+suffix;

    return abs;

errrr - 我不知道为什么我在计算背面时使用StringBuilder,但你明白了。是这样的。

【讨论】:

【参考方案4】:

您可以使用render="@all"render="@form" 分别渲染所有内容或整体。

或者,您可以将要更新的内容的绝对 ID 作为参数传递到组件中。这样可以保持灵活性,无需重新渲染过多的页面。

【讨论】:

@all 工作,用 JBoss AS 7.1.0.CR1b 测试。但在大多数情况下它太重了【参考方案5】:

在 JSF 2.0 中,您可以在 EL 中使用隐式的 cccomponent 对象。为了获取任何组件的完整客户端 ID,请执行以下操作:

#component.clientId

要检索复合组件的客户端 ID,请执行以下操作:

#cc.clientId

同样的方法,你也可以用#cc.parent 获取父级。在这种情况下,这可能就是您想要的。如需更长的答案,请参阅Acquire full prefix for a component clientId inside naming containers with JSF 2.0。

【讨论】:

以上是关于JSF 2.0 复合组件 - ajax 渲染参数 OUTSIDE 组件定义的主要内容,如果未能解决你的问题,请参考以下文章

jsf 2.0 自定义组件/标签不复合

嵌套 JSF 复合组件中的 AJAX

JSF 2 - 如何将 Ajax 侦听器方法添加到复合组件接口?

JSF拒绝处理深层嵌套的复合组件。不,真的:“JSF1098:[...]这浪费了处理器时间[...]”

JSF 2——在 f:ajax 上具有可选监听器属性的复合组件

JSF 复合组件 <f:ajax> 包含未知 id - 无法在组件的上下文中找到它