【问题标题】:JSF 2.0 Composite components - ajax render parameter OUTSIDE component definitionJSF 2.0 复合组件 - ajax 渲染参数 OUTSIDE 组件定义
【发布时间】: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 似乎在组件边界处终止搜索

标签: java jsf-2


【解决方案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

        【讨论】:

          猜你喜欢
          • 2011-12-12
          • 1970-01-01
          • 1970-01-01
          • 2011-09-28
          • 2011-10-11
          • 2013-01-24
          • 1970-01-01
          • 2012-08-16
          • 2013-07-31
          相关资源
          最近更新 更多