【问题标题】:Ajax Listener event valueChange seems to be firing onClick instead of onChangeAjax 侦听器事件 valueChange 似乎正在触发 onClick 而不是 onChange
【发布时间】:2012-01-08 09:23:29
【问题描述】:

我有一个要显示的问题嵌套列表。最初,我显示 1 级问题,然后根据用户对其父问题的回答显示子问题。所有问题都有一个单选按钮,有些问题有一个输入框,用于在用户选择“是”时显示附加信息

这是我的带有嵌套数据表的 JSF 代码。请注意,为了简化论坛上的问题,我已经删除了这些问题的格式,因此如果您将此代码复制到自己的环境中并运行代码,这些可能看起来“不漂亮”:

<h:dataTable id="questionTable" var="q" value="#{generalQuestionBean2.questions.questions}">
<h:column><h:panelGroup id="questionGrp">
#{q.question} <h:selectOneRadio value="#{q.answer}">
<f:selectItem itemValue="1" itemLabel="Yes"/>
<f:selectItem itemValue="0" itemLabel="No"/>
<f:ajax event="valueChange" execute="@form"
    render="questionGrp"
    listener="#{generalQuestionBean2.reset}"/>
</h:selectOneRadio> <h:inputText value="#{q.addnInfo}"
rendered="#{q.answer eq '1' and q.field ne 'otherCov'}"></h:inputText>

<h:panelGroup id="questionGrpSubs" rendered="#{q.addnQuestions ne null and q.answer eq '1'}">
<h:dataTable id="subQuestionTable" var="subq" value="#{q.addnQuestions}">
<h:column><h:panelGroup id="subQuestionGrp">
->#{subq.question} <h:selectOneRadio id="answer" value="#{subq.answer}"> 
 <f:selectItem itemValue="1" itemLabel="Yes"/>
 <f:selectItem itemValue="0" itemLabel="No"/>
 <f:ajax event="valueChange" execute="@form"
    render="subQuestionGrp"
    listener="#{generalQuestionBean2.reset}"/>
</h:selectOneRadio><h:inputText value="#{subq.addnInfo}"
rendered="#{subq.answer eq '1' and subq.field ne 'voluntaryComp' and subq.field ne 'uslh'}"></h:inputText>

<h:panelGroup id="questionGrpSubs2" rendered="#{subq.addnQuestions ne null and subq.answer eq '1'}">
<h:dataTable id="sub2QuestionTable" var="sub2q" value="#{subq.addnQuestions}">
<h:column><h:panelGroup id="sub2QuestionGrp">
-->#{sub2q.question} <h:selectOneRadio id="answer" value="#{sub2q.answer}"> 
 <f:selectItem itemValue="1" itemLabel="Yes"/>
 <f:selectItem itemValue="0" itemLabel="No"/>
 <f:ajax event="valueChange" execute="@form"
    render="sub2QuestionGrp"
    listener="#{generalQuestionBean2.reset}"/>
</h:selectOneRadio><h:inputText value="#{sub2q.addnInfo}"
rendered="#{sub2q.answer eq '1'}"></h:inputText>

</h:panelGroup></h:column>
</h:dataTable></h:panelGroup>
</h:panelGroup></h:column>
</h:dataTable></h:panelGroup>
</h:panelGroup></h:column>
</h:dataTable>

下面是 backing bean 上的 reset 函数代码:

private void reset(AjaxBehaviorEvent event) {
    FacesContext context = FacesContext.getCurrentInstance();
    String id = event.getComponent().getClientId(context);
    String[] tokens = id.split("[:]+");
    int qId = -1;
    int subqId = -1;
    int sub2qId = -1;
    for (int i = 0; i < tokens.length; i++) {
        if(tokens[i].equals("questionTable")) 
            qId = Integer.parseInt(tokens[i+1]);
        if(tokens[i].equals("subQuestionTable"))
            subqId = Integer.parseInt(tokens[i+1]);
        if(tokens[i].equals("sub2QuestionTable"))
            sub2qId = Integer.parseInt(tokens[i+1]);

    }
    Question q = questions.getQuestion(qId);
    Question processQ = q;
    String defaultSubAnswer = getDefaultSubAnswer(q.getField());
    Question subq;
    Question subq2;
    if(subqId > -1) {
        subq = q.getAddnQuestions().get(subqId);
        processQ = subq;
        if(sub2qId > -1) {
            subq2 = subq.getAddnQuestions().get(sub2qId);
            processQ = subq2;
        }
    }
    resetValue(processQ, defaultSubAnswer);
}


private void resetValue(Question q, String defaultSubAnswer) {
    q.setAddnInfo("");
    if(q.getAddnQuestions() != null) {
        for (int i = 0; i < q.getAddnQuestions().size(); i++) {
            Question subq = q.getAddnQuestions().get(i);
            subq.setAnswer(defaultSubAnswer);
            resetValue(subq, defaultSubAnswer);
        }
    }
}

问题来了:

ajax 事件应默认为“valueChange”。如果我单击“是”然后再次单击“是”,则不会发生 ajax 调用,对吗?但它是,因为附加信息框正在清除基于重置功能。

我最初尝试向重置函数添加条件以检查单击按钮的值,并且仅在答案为“0”(否)时重置 addnInfo 值和子问题。但这会导致渲染出现问题,因为 ajax 调用会将输入框和子问题渲染为隐藏,并且该值将保留在前端,即使它们在后备 bean 上被重置。当他们重新渲染到最前面时,显示的是保留的值,而不是支持 bean 中的值。

另一个尝试是使用 ValueChangeListener 来重置值。但这仍然存在与重新渲染时保留的值相同的问题。

我尝试了 3 种不同的方法(如上所列),但都失败了。我愿意听取任何这些或可能的其他解决方案的解决方案。请记住,用户的格式限制使我可以使用的选项更少。

【问题讨论】:

    标签: ajax jsf-2


    【解决方案1】:

    Ajax 监听器事件 valueChange 似乎正在触发 onClick 而不是 onChange

    这确实是默认的 valueChange 事件,由相应 JSF 组件分类的单选按钮和复选框使用。检查生成的 HTML 源代码,您会看到它与 onclick 挂钩。 JSF 在默认情况下这样做的原因对于复选框是明确的,但乍一看对于单选按钮并不完全清楚,因为它们无论如何都不能取消勾选。真正的原因是这样做是为了确保 IE6/7 兼容性,因为 onchange 在该浏览器中第一次点击时不会被触发。

    如果您不关心 IE6/7 用户(但其分布最近急剧下降),请将其更改为 event="change"

    <f:ajax event="change" ... />
    

    这样 JSF 将改为在 onchange 上生成事件处理程序。


    更新:您可以使用jQuery.on('change') 函数绑定器,它将修复change 事件上的IE6/7 错误行为。如果您还没有使用 jQuery,请在 &lt;h:head&gt; 中包含以下内容:

    <script src="http://code.jquery.com/jquery-latest.min.js"></script>
    

    并在加载时执行此函数:

    $(function() {
        $(':radio').each(function() {
            var handler = this.onclick;
            this.onclick = null;
            $(this).on('change', handler);
        });
    });
    

    这将基本上对于每个单选按钮将 JSF 生成的 onclick 属性移动到由 jQuery 管理的 change 事件处理程序,以便它在所有浏览器中都能正常工作,包括 IE6/7。

    我们当然也可以使用纯 JS 来实现,但这需要大量样板代码和跨浏览器敏感代码。

    【讨论】:

    • 很遗憾,我们确实需要兼容 IE,因此上述解决方案将不起作用。我确实在 Firefox 上尝试过,效果很好,但对于 IE(我们的很多用户都在使用)来说,它是不可取的。
    • 这需要一些优秀的基于 JavaScript 的浏览器嗅探和黑客攻击...
    猜你喜欢
    • 2020-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-18
    • 2010-12-27
    • 2017-03-01
    • 1970-01-01
    相关资源
    最近更新 更多