它的工作方式
努力寻找解决方案,我发现我只是忘记了使用组件中的前导 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)
}
顺便提一句。通过复合组件要复杂得多,我将此示例简化为相关部分。