我有一个使用动态表单的页面,在该页面上以编程方式创建了组件树(这个问题不值得讨论),我需要呈现的某些输入控件需要ajax处理程序。
xhtml片段(包含<ui:include>在另一个片段中)是:
<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>
基于其他SO解答,我有以下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 }
这可以正确渲染,我看到:
<input type="radio" onchange="mojarra.ab(this,event,'change',0,'probeDiv2')" value="0" id="answer_1:0" name="answer_1">
但是,单击单选按钮会给我一个JavaScript控制台错误: reference error: mojarra is not defined
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>
这项工作正常,萤火虫网络监视器显示单选按钮上的ajax事件已发布到应用程序。
所以,最后,我的问题是:
如何以编程方式强制包含ajax javascript库并免除我当前正在使用的可怕骇客?
注意:我对以“不要使用动态生成的组件”开头的任何答案都不感兴趣-由于多种原因,这不是一个选择。
基本上,您需要这样做:
<h:outputScript library="javax.faces" name="jsf.js" target="head" />
该脚本mojarra在jsf包含JSF ajax脚本的标准名称空间中包含定义。
mojarra
jsf
您可以在<h:head>主模板的中显式声明它,如有必要,可以通过<ui:define>/进行声明<ui:include>。jsf.js如果视图已隐式要求,它将不会加载文件的重复副本。
<h:head>
<ui:define>
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");
同样在这里,jsf.js如果视图已经隐式需要,它将不会加载文件的重复副本。
无关 的具体问题,你应该更喜欢<f:event type="postAddToView">了binding,当你需要以编程方式填充组件树:
<f:event type="postAddToView">
binding
<h:panelGroup id="id_Group1" layout="block"> <f:event type="postAddToView" listener="#{questionaire.populateGroup1}" /> </h:panelGroup>
与
public void populateGroup1(ComponentSystemEvent event) { HtmlPanelGorup group1 = (HtmlPanelGroup) event.getComponent(); // ... }
这样可以确保在恰好适当的时机填充树,并确保getter不受业务逻辑的影响,并避免#{questionaire}在比请求范围更广的范围内潜在的“重复组件ID”麻烦,并使Bean不受UIComponent属性的影响。当组件作为可序列化bean的属性保存时,转弯避免了潜在的序列化麻烦和内存泄漏。
#{questionaire}
UIComponent