4

我有一个使用动态表单的页面,我在其中以编程方式创建组件树(在这个问题中没有争议) 我需要呈现的一些输入控件需要一个 ajax 处理程序。

xhtml 片段(由<ui:include>来自另一个片段的 a 包含)是:

<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 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
    }

这可以正确渲染,我看到:

<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

现在,如果我修改 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>

这有效,firebug 网络监视器显示我的 ajax 事件从单选按钮发布到应用程序。

所以,最后,我的问题:

我如何以编程方式强制包含 ajax javascript 库并免除我目前使用的可怕黑客攻击?

注意:我对任何以“不要使用动态生成的组件”开头的答案都不感兴趣——出于多种原因,这不是一个选项。

4

1 回答 1

9

基本上,你需要这个:

<h:outputScript library="javax.faces" name="jsf.js" target="head" />

该脚本包含包含 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");

jsf.js同样在这里,如果视图已经隐式需要,它不会加载文件的重复副本。


与具体问题无关<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 的属性保存时,turn 避免了潜在的序列化问题和内存泄漏。

于 2013-11-13T17:36:32.393 回答