JSF2.0 - 具有可选方法表达式的复合组件

时间:2013-03-14 21:00:26

标签: jsf-2 java-ee-6 composite-component

我正在实现一个复合组件,我发现了一个我找不到解决方案的问题。

我指定了页面作者可以传递或不传递的属性,但我无法指定方法属性(Action的方法表达式),如果未传递,则复合组件不使用composite:implementation标签中的method属性。

这是我的代码:

<composite:interface>
    <composite:attribute name="namePrompt" required="true"/>
    <composite:attribute name="actionMethod" method-signature="java.lang.String  action()" required="false"/>
    <composite:attribute name="showComponent" default="false"/>
</composite:interface>

<composite:implementation>
    <div>
       <p:commandLink actionListener="#{cc.attrs.actionMethod}"
                      rendered="#{cc.attrs.showComponent}"
                      >
            <h:outputText value="#{cc.attrs.namePrompt}"/>    
       </p:commandLink>
    </div>
</composite:implementation>

使用它时,我没有指定“actionMethod”属性。像这样:

<util:foo namePrompt="SomeName" showComponent="true"/>

但我收到错误消息:

javax.faces.FacesException: Unable to resolve composite component from using page using EL expression '#{cc.attrs.actionMethod}'

有办法做到这一点吗?

5 个答案:

答案 0 :(得分:10)

您必须创建两个p:commandLink元素,并根据参数的定义有条件地渲染它们:

<p:commandLink actionListener="#{cc.attrs.actionMethod}" rendered="#{!empty cc.getValueExpression('actionMethod') and cc.attrs.showComponent}">
  <h:outputText value="#{cc.attrs.namePrompt}"/>
</p:commandLink>
<p:commandLink rendered="#{empty cc.getValueExpression('actionMethod')}">
  <h:outputText value="#{cc.attrs.namePrompt}"/>
</p:commandLink>

答案 1 :(得分:5)

将方法签名返回类型更改为java.lang.Object并添加&#34; null&#34;作为默认值。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label>Java</label>
<br />
<label>Python</label>
<br />
<label>Perl</label>
<br />

<script type="text/javascript">
  var jq = jQuery.noConflict();
  jq("label").after(" Programing");
</script>

没有方法:

<composite:interface>
    <composite:attribute name="namePrompt" required="true"/>
    <composite:attribute name="actionMethod" method-signature="java.lang.Object action()" required="false" default="null"/>
    <composite:attribute name="showComponent" default="false"/>
</composite:interface>

<composite:implementation>
    <div>
       <p:commandLink actionListener="#{cc.attrs.actionMethod}"
                      rendered="#{cc.attrs.showComponent}"
                      >
            <h:outputText value="#{cc.attrs.namePrompt}"/>    
       </p:commandLink>
    </div>
</composite:implementation>

使用方法:

<util:foo namePrompt="SomeName" showComponent="true"/>

答案 2 :(得分:3)

另一种解决方案是使用操作方法创建自己的组件类型。例如:

<composite:interface componentType="myButton">
    <composite:attribute name="namePrompt" required="true"/>
    <composite:attribute name="actionMethod" method-signature="java.lang.String  action()" required="false"/>
    <composite:attribute name="showComponent" default="false"/>
</composite:interface>

<composite:implementation>
    <div>
       <p:commandLink actionListener="#{cc.action()}" rendered="#{cc.attrs.showComponent}">
          <h:outputText value="#{cc.attrs.namePrompt}"/>    
      </p:commandLink>
   </div>
</composite:implementation>

componentType必须如下所示:

@FacesComponent("myButton")
public class MyButton extends UINamingContainer {

    public MyButton () {
    }

    public String action() {
        MethodExpression me = (MethodExpression) this.getAttributes().get("actionMethod");
        if (me != null) {
            try {
                Object result = me.invoke(FacesContext.getCurrentInstance().getELContext(),     null);
                if (result instanceof String) {
                    return (String) result;
                }
            } catch (ValidatorException ve) {
                throw ve;
            }
        }
        return null;
    }
}

答案 3 :(得分:1)

有同样的确切错误,并且我的组件也需要一个可选的操作方法。

所以我尝试使用method-signature在composite属性上添加一个default参数,指向相应FacesComponent类上的一个方法,它运行得很好!

组件:

<composite:interface componentType="myButton">
    <composite:attribute name="namePrompt" required="true"/>
    <composite:attribute name="actionMethod" method-signature="java.lang.String  action()" required="false" default="#{cc.dummyAction}"/>
    <composite:attribute name="showComponent" default="false"/>
</composite:interface>

<composite:implementation>
    <div>
       <p:commandLink action="#{cc.attrs.actionMethod}"
                      rendered="#{cc.attrs.showComponent}"
                      >
            <h:outputText value="#{cc.attrs.namePrompt}"/>    
       </p:commandLink>
    </div>
</composite:implementation>

FacesComponent类:

@FacesComponent("myButton")
public class MyButton extends UINamingContainer {

    public MyButton () {
    }

    public String dummyAction() {
       return "";
    }

}

答案 4 :(得分:0)

避免将方法放入复合材料中。如果您需要这样做,请将具有该方法的类放入Composite中,并像这样使用它:

<composite:interface>
   <composite:attribute name="classWithMethod" 
                        method-signature="java.lang.String"/>
</composite:interface>

执行:

<composite:implementation>
   <div>
      <p:commandLink 
         actionListener="#{cc.attrs.classWithMethod.actionMethod}">    
      </p:commandLink>
   </div>
</composite:implementation>

为我工作! :D