1

它的工作方式

努力寻找解决方案,我发现我只是忘记了使用组件中的前导 h:head 标记。添加它们使所有错误消失。因此,对于一个完整的解决方案,这是我的最后一个代码:

  • 复合组件
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
    <composite:attribute name="value" required="true"  />
    <composite:attribute name="size" required="false" default="20" />
    <composite:clientBehavior name="change" event="change" targets="input" />
</composite:interface>
<composite:implementation>
    <h:inputText id="input" value="#{cc.attrs.value}" size="#{cc.attrs.size}" />
</composite:implementation>

  • 豆子
@ManagedBean
@SessionScoped
public class MyBean
{
private String value1;
private String value2;
private String value3;

public String exec()
{
    this.value2 = value3;
    return "";
}

public void listenAjax(AjaxBehaviorEvent e)
{
    UIInput i = (UIInput) e.getComponent();     
    value2 = (String) i.getValue();
    System.out.println("ajax value = " + i.getValue());
    System.out.println("value1 = " + value1);
    System.out.println("value2 = " + value2);
    System.out.println("value3 = " + value3);
}

public String getValue3()
{
    return value3;
}

public String getValue2()
{
    return value2;
}

public String getValue1()
{
    return value1;
}

public void setValue1(String value1)
{
    this.value1 = value1;
}

public void setValue3(String value3)
{
    this.value3 = value3;
}
}
  • 调用 xhtml 文件
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:test="http://java.sun.com/jsf/composite/test">
<h:head>
</h:head>
<h:body>
<h:form id="form">
    <h:panelGrid columns="2">
        <h:outputText value="value3" />
        <h:inputText value="#{myBean.value3}">
            <f:ajax event="change" render="see" listener="#{myBean.listenAjax}" />
        </h:inputText>
        <h:outputText value="value1" />
        <test:test value="#{myBean.value1}">
            <f:ajax event="change" render=":form:see" listener="#{myBean.listenAjax}" />
        </test:test>
        <h:outputText value="value2" />
        <h:outputText id="see" value="#{myBean.value2}" />
        <h:outputText value="" />
        <h:commandButton action="#{myBean.exec}" value="set" />
    </h:panelGrid>
</h:form>
</h:body>
</html>

最后,感谢所有给我一些提示并帮助我找出错误的人。

改进步骤 2

现在重新设计组件我有这个:

  • 复合组件:
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
    <composite:attribute name="value" required="true"  />
    <composite:attribute name="size" required="false" default="20" />
    <composite:clientBehavior name="change" event="change" targets="input" />
</composite:interface>
<composite:implementation>
    <h:inputText id="input" value="#{cc.attrs.value}" size="#{cc.attrs.size}" />
</composite:implementation>

  • 托管豆:
@ManagedBean
@SessionScoped
public class MyBean {
private String value1;
private String value2;
private String value3;

public String exec()
{
    this.value2 = value3;
    return "";
}

public void listen(AjaxBehaviorEvent e)
{
    UIInput i = (UIInput) e.getComponent();     
    value2 = (String) i.getValue();
    System.out.println("ajax value = " + i.getValue());
    System.out.println("value1 = " + value1);
    System.out.println("value2 = " + value2);
    System.out.println("value3 = " + value3);
}

public String getValue3()
{
    return value3;
}

public String getValue2()
{
    return value2;
}

public String getValue1()
{
    return value1;
}

public void setValue1(String value1)
{
    this.value1 = value1;
}

public void setValue3(String value3)
{
    this.value3 = value3;
}

}

  • 用法:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:test="http://java.sun.com/jsf/composite/test">
<h:body>
<h:form>
    <test:test value="#{myBean.value1}">
        <f:ajax event="change" render=":out" listener="#{myBean.listen}" />
    </test:test>
    <h:inputText value="#{myBean.value3}">
        <f:ajax event="change" render=":out" listener="#{myBean.listen}" />
    </h:inputText>
    <h:commandButton action="#{myBean.exec}" value="set" />
</h:form>
<h:outputText id="out" value="#{myBean.value2}" />
</h:body>
</html>

然而,没有对表单之外的组件进行 ajax 响应(在日志窗口中没有结果)。这让我很困惑,我怎样才能让它工作?

改进步骤 1(旧)

所以我尝试改进我的代码,将复合组件更改为

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
    <composite:attribute name="value" required="true" />
    <composite:attribute name="size" required="false" default="20" />
    <composite:clientBehavior name="change" event="change" targets="#{cc.clientId}:input" />
</composite:interface>
<composite:implementation>
    <h:inputText id="input" value="#{cc.attrs.value}" size="#{cc.attrs.size}" />
</composite:implementation>

我的电话是

<my:test value="#{test.value1}">
  <f:ajax event="change" render=":out" listener="#{test.listen}" />
</my:test>
<h:outputText id="out" value="#{test.value2}" />

结果完全没有任何反应。我可以做些什么来完成这项工作?

原帖*

我想让我的复合组件使用 AJAX。我用谷歌搜索了很多,甚至在 stackoverflow 上也找到了一些解决方案,但它们似乎都只适用于按钮。这里我有一个inputText组件,如何给我的组件一个 AJAX 事件监听器?执行我的示例(见下文)会出现此错误:

com.sun.faces.lifecycle.InvokeApplicationPhase execute
WARNING: 0
java.lang.ArrayIndexOutOfBoundsException: 0
at org.apache.el.parser.AstValue.convertArgs(AstValue.java:320)
at org.apache.el.parser.AstValue.invoke(AstValue.java:274)
at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:274)
at com.sun.faces.facelets.el.ContextualCompositeMethodExpression.invoke(ContextualCompositeMethodExpression.java:187)
at com.sun.faces.facelets.tag.TagAttributeImpl$AttributeLookupMethodExpression.invoke(TagAttributeImpl.java:473)
at com.sun.faces.facelets.tag.jsf.core.AjaxBehaviorListenerImpl.processAjaxBehavior(AjaxHandler.java:459)
at javax.faces.event.AjaxBehaviorEvent.processListener(AjaxBehaviorEvent.java:113)
at javax.faces.component.behavior.BehaviorBase.broadcast(BehaviorBase.java:106)
at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:809)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:800)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1292)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:181)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:645)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)

我的复合组件:

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
    <composite:attribute name="value" required="true" />
    <composite:attribute name="size" required="false" default="20" />
    <composite:attribute name="enableAjax" required="false" default="false" />
    <composite:attribute name="ajaxRender" required="false" />
    <composite:attribute name="ajaxListener" required="false" method-signature="void listen(javax.faces.event.AjaxBehaviorEvent)" />
</composite:interface>
<composite:implementation>
    <h:inputText id="input" value="#{cc.attrs.value}" size="#{cc.attrs.size}">
        <f:ajax event="change" render="#{cc.attrs.ajaxRender}" listener="#{cc.attrs.ajaxListener}" disabled="#{!cc.attrs.enableAjax}" />
    </h:inputText>
</composite:implementation>

我的电话:

<my:test value="#{test.value1}" ajaxRender=":out" ajaxListener="#{test.listen}" enableAjax="true" />
<h:outputText id="out" value="#{test.value2}" />

我的豆子:

@ManagedBean
@SessionScoped
public class Test {
  private String value1;
  private String value2;
  ...
  public void listen(AjaxBehaviorEvent e)
  {
    value2 = (String) ((UIInput) e.getComponent()).getValue();
  }
  ... (getter & setter)
}

顺便提一句。通过复合组件要复杂得多,我将此示例简化为相关部分。

4

2 回答 2

3

<cc:clientBehavior>应该工作。你targets只是错的。

<composite:clientBehavior name="change" event="change" targets="#{cc.clientId}:input" />

它必须与组合本身相关,而不是与父/viewroot 或其他任何东西相关(因为理论上这将需要在每次将组合组件放入不同的命名容器父级时编辑它!)。

因此,所以

<composite:clientBehavior name="change" event="change" targets="input" />
于 2013-02-14T12:25:46.103 回答
1

如果我们查看您的复合组件定义(尤其是ajaxListener属性),您定义了一个方法AjaxBehaviorEvent(这是这种事件侦听器的正确签名),但在使用您的组件时,您将属性定义为:

ajaxListener="#{test.listen}"

所以,没有参数 - 这就是抛出这个异常的地方(试图找到方法的参数)。

有了这个你的用例,你应该稍微改变你的组件定义。所以改变:

<composite:attribute name="ajaxListener" required="false" method-signature="void listen(javax.faces.event.AjaxBehaviorEvent)" />

像这样:

<composite:attribute name="bean" required="false" type="java.lang.Object" />
<composite:attribute name="ajaxListener" required="false" type="java.lang.String" />

还将标签中的listener属性更改为:f:ajax

listener="#{cc.attrs.bean[cc.attrs.ajaxListener]}"

最后改变你的复合组件的使用方式:

<my:test value="#{test.value1}" ajaxRender=":out" ajaxListener="listen" bean="#{test}" enableAjax="true" />
于 2013-02-13T10:26:08.630 回答