【问题标题】:<a4j:jsFunction> calling returns undefined from server<a4j:jsFunction> 调用从服务器返回未定义
【发布时间】:2016-05-28 04:33:14
【问题描述】:

在我的托管 Bean 中,我有一个简单的布尔方法:

public class UploadBean {

    // ...

    public boolean getPossuiNotasFiscaisNaoTransmitidas() {
        boolean result = false;

        // Some computation ...

        return result;
    }

}

在我的 XHTML 页面中,我使用的是 RichFaces 3.3.3 tabPanel。在特定选项卡中,我需要确认我是否真的打开它:

    <a4j:jsFunction name="possuiNotasFiscaisNaoTransmitidas" action="#{uploadBean.getPossuiNotasFiscaisNaoTransmitidas}" immediate="true" process="tab-10" ajaxSingle="true" reRender="tab-10"/>
    <a4j:loadScript src="../../js/orcamentoVistoria.js"/>
    <rich:tabPanel id="abas" switchType="ajax" >
        <!-- many tabs... -->
        <rich:tab 
                id="tab-10" 
                name="tab-10" 
                ontabenter="return prosseguirAbaNotasFiscais();"
                ontableave="return prosseguirAbaNotasFiscais();" >
            <!-- content -->
        </rich:tab>
    </rich:tabPanel>

orcamentoVistoria.js中的函数prosseguirAbaNotasFiscais()调用托管bean方法:

function prosseguirAbaNotasFiscais() {
    console.info("prosseguirAbaNotasFiscais: Entrando");                                // LOG 1
    var serverResponse = possuiNotasFiscaisNaoTransmitidas();
    console.info("prosseguirAbaNotasFiscais: serverResponse? " + serverResponse);       // LOG 2
    var result = serverResponse ? confirm("Proceed?"): true;
    console.info("prosseguirAbaNotasFiscais: Resultado? " + result);                    // LOG 3
    return result;
}

我的预期:当我进入(或离开)标签页时,页面会调用托管 bean 方法。如果它的回答是真的,它会询问用户是否想继续进入/离开。如果它的答案是假的,那么标签将直接进入/离开。

我真正得到的:当我进入(或离开)标签页时,页面显然调用了托管 bean 方法。至少,在调试中,我可以看到正在执行的方法(实际上是很多次)。但是,在 JS 返回(LOG 2 行)中,serverResponse 变量是未定义的。就像页面没有等待服务器响应一样。因此 JS 函数将始终返回 true 并且选项卡将始终直接进入/离开。

那么,我该怎么办?它是&lt;a4j:jsFunction&gt; 标签中的某个特定属性吗?

谢谢

拉斐尔·阿方索

2016 年 2 月 17 日更新

@Makhiel,感谢您的建议。但是,我需要的是通过某种方式,在执行oncomplete 之后,允许或不允许选项卡更改。但是(至少我能理解),只有通过标签中的ontabenterontableave 才有可能。

按照 Makhiel 的建议,我在代码中做了以下建议:

托管 Bean

public class UploadBean {

    private boolean questionarAbaNotasFiscais = false;

    // ...

    public boolean getPossuiNotasFiscaisNaoTransmitidas() {
        this.questionarAbaNotasFiscais = false;

        // Some computation. It can change questionarAbaNotasFiscais or not ...

        return this.questionarAbaNotasFiscais;
    }

    // ...

    public boolean isQuestionarAbaNotasFiscais() {
        return questionarAbaNotasFiscais;
    }
}

XHTML:

<a4j:jsFunction name="possuiNotasFiscaisNaoTransmitidas" action="#{uploadBean.getPossuiNotasFiscaisNaoTransmitidas}"
    data="#{uploadBean.questionarAbaNotasFiscais}" oncomplete="questionarAbaNotasFiscais = data; console.timeEnd('consulta');console.info('servidor retornou ' + questionarAbaNotasFiscais)"
    immediate="true" process="tab-10" ajaxSingle="true" reRender="tab-10"/>
<a4j:loadScript src="../../js/orcamentoVistoria.js"/>
<rich:tabPanel id="abas" switchType="ajax" >
    <!-- many tabs... -->
    <rich:tab 
            id="tab-10" 
            name="tab-10" 
            ontabenter="return prosseguirAbaNotasFiscais();"
            ontableave="return prosseguirAbaNotasFiscais();" >
        <!-- content -->
    </rich:tab>
</rich:tabPanel>

Java 脚本

var questionarAbaNotasFiscais = null;

function prosseguirAbaNotasFiscais() {
//  questionarAbaNotasFiscais = null;
    console.info("prosseguirAbaNotasFiscais: Entrando");
    console.time("consulta");
    var b = possuiNotasFiscaisNaoTransmitidas();

    console.info("prosseguirAbaNotasFiscais: Esperando retorno. b = " + b);
    console.time("watingReturn")
    while(typeof questionarAbaNotasFiscais === null) {
        // wait for return
    }
    console.timeEnd("watingReturn")
    console.info("prosseguirAbaNotasFiscais: respostaServidor? " + questionarAbaNotasFiscais);
    var result = questionarAbaNotasFiscais ? confirm(msgNotasNaoTransmitidas): true;
    console.info("prosseguirAbaNotasFiscais: Resultado? " + result);

    questionarAbaNotasFiscais = null;
    return result;
}

我想要什么prosseguirAbaNotasFiscais() 函数调用possuiNotasFiscaisNaoTransmitidas() 并等到全局变量questionarAbaNotasFiscais 填入oncomplete 并继续等待。一旦在这个声明中和prosseguirAbaNotasFiscais()函数的末尾questionarAbaNotasFiscais总是设置为null,等待总是执行上面的循环,只有当oncomplete被执行时才结束。

我得到了什么:当prosseguirAbaNotasFiscais() 被执行时,调用服务器函数,但显然没有等待服务器返回。我观察到首先调用 JS 函数,重新加载页面,然后调用服务器函数。

好的,服务器函数异步执行。那么有没有办法强制等到服务器功能呢?

谢谢,

拉斐尔·阿方索

【问题讨论】:

  • 您可以使用switchType="client" 对其进行测试。您可以在ontableave="if (#{bean.method} &amp;amp;&amp;amp; !confirm('Are you sure you want to proceed?')) return false;" 等属性中调用 bean 方法
  • @VasilLukach 它不是这样工作的,EL 表达式将在页面呈现时进行评估,而不是在“tableave”事件触发时进行评估
  • @Makhiel,这种疯狂的结构在真正的 JSF 1.2 应用程序中的 commandButton 属性中确实有效。我从未在 tabPanel 中测试过它。这只是建议。
  • @VasilLukach 有一些属性只在请求处理期间进行评估,但如果它像那样工作,你就不需要命令按钮,你只需写 &lt;button onclick="#{bean.method}" /&gt;
  • 您可以描述您想要做什么,而不是描述您希望该功能如何工作?阻止用户切换到另一个选项卡?你需要去服务器吗?

标签: ajax richfaces jsf-1.2


【解决方案1】:
var serverResponse = possuiNotasFiscaisNaoTransmitidas();

这不行,JavaScript 方法不能直接在服务器上执行方法并返回结果。 a4j:jsFunction 所做的是向服务器发送 AJAX 请求,然后服务器发回响应。它是异步的,所以是的,页面并没有在服务器上等待(如果它这样做会很糟糕)。

不是从 bean 方法返回结果,而是将结果保存到 bean 属性,然后使用 @data:

<a4j:jsFunction data="#{bean.result}"
    name="possuiNotasFiscaisNaoTransmitidas" 
    oncomplete="if (data) {doSomething();}"
    … />

“oncomplete”代码将在服务器返回响应时执行。

我不确定结果值是否会直接在data变量中,最好用console.log检查。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多