我有一个使用动态表单的页面,我以编程方式创建组件树(在这个问题中没有讨论)我需要渲染的一些输入控件需要一个ajax处理程序.
xhtml片段(由<ui:include>另一个片段包含)是:
<ui:composition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://xmlns.jcp.org/jsf/passthrough">
<h:panelGroup id="id_Group1" binding="#{questionaire.group1}" layout="block"/>
</ui:composition>
Run Code Online (Sandbox Code Playgroud)
基于其他SO anwsers,我有以下bean代码:
public HtmlPanelGroup getGroup1() {
// irrelevant code omitted
HtmlSelectOneRadio selectUI = new HtmlSelectOneRadio();
AjaxBehavior valueChangeAction = (AjaxBehavior)FacesUtils.getApplication().createBehavior(AjaxBehavior.BEHAVIOR_ID);
valueChangeAction.addAjaxBehaviorListener(new ProbeQuestionListener(currentQuestion, "probeDiv" + questionNumber));
selectUI.addClientBehavior("change", valueChangeAction);
valueChangeAction.setRender(Collections.singletonList("probeDiv" + questionNumber));
// further code to customise the control, create the panel group and probe div and wire everything together omitted
}
Run Code Online (Sandbox Code Playgroud)
这正确呈现,我看到:
<input type="radio" onchange="mojarra.ab(this,event,'change',0,'probeDiv2')" value="0" id="answer_1:0" name="answer_1">
Run Code Online (Sandbox Code Playgroud)
但是,单击单选按钮会给我一个javascript控制台错误: reference error: mojarra is not defined
现在,如果我修改xhtml以包含"正常"ajax控件,例如
<ui:composition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://xmlns.jcp.org/jsf/passthrough">
<h:panelGroup id="id_Group1" binding="#{questionaire.group1}" layout="block"/>
<!-- include a hacky hidden ajax field to force inclusion of the ajax javascript -->
<h:panelGroup layout="block" id="hiddenAjaxDiv" style="display:none">
<h:inputText id="hiddenAjax">
<f:ajax execute="hiddenAjax" render="hiddenAjaxDiv" />
</h:inputText>
</h:panelGroup>
</ui:composition>
Run Code Online (Sandbox Code Playgroud)
这工作和firebug网络监视器显示我从单选按钮发送到应用程序的ajax事件.
最后,我的问题是:
我如何以编程方式强制包含ajax javascript库并免除我目前正在使用的可怕黑客攻击?
注意:我对任何以"不使用动态生成的组件"开头的答案不感兴趣 - 由于多种原因,这不是一个选项.
基本上,你需要这个:
<h:outputScript library="javax.faces" name="jsf.js" target="head" />
Run Code Online (Sandbox Code Playgroud)
该脚本包含包含JSF ajax脚本mojarra的标准jsf命名空间中的定义.
您可以在<h:head>主模板中明确声明它,如有必要,可以通过<ui:define>/ <ui:include>.jsf.js如果视图已隐式要求,它将不会加载文件的重复副本.
您甚至可以以编程方式创建它:
UIComponent jsfjs = new UIOutput();
jsfjs.getAttributes().put("library", "javax.faces");
jsfjs.getAttributes().put("name", "jsf.js");
jsfjs.setRendererType("javax.faces.resource.Script");
FacesContext context = FacesContext.getCurrentInstance();
context.getViewRoot().addComponentResource(context, jsfjs, "head");
Run Code Online (Sandbox Code Playgroud)
此外,jsf.js如果视图已隐式要求,它将不会加载文件的重复副本.
无关的具体问题,你应该更喜欢<f:event type="postAddToView">了binding,当你需要以编程方式填充组件树:
<h:panelGroup id="id_Group1" layout="block">
<f:event type="postAddToView" listener="#{questionaire.populateGroup1}" />
</h:panelGroup>
Run Code Online (Sandbox Code Playgroud)
同
public void populateGroup1(ComponentSystemEvent event) {
HtmlPanelGorup group1 = (HtmlPanelGroup) event.getComponent();
// ...
}
Run Code Online (Sandbox Code Playgroud)
这保证了树在恰当的时刻填充,并保持getter没有业务逻辑,并避免#{questionaire}在比请求范围更广的范围内潜在的"重复组件ID"麻烦,并保持bean没有UIComponent属性当组件被保存为可序列化bean的属性时,转向避免了潜在的序列化问题和内存泄漏.