Oracle APEX - 如何确保回调在页面提交之前完成

Oracle APEX - how to ensure callback finishes before the page is submitted

我有一个带有自定义按钮的交互式网格。该按钮在单击时处理选定的行:

循环遍历所有选定的行,如果行符合条件,则对每一行执行回调。

apex.server.process
 ("process_selected_callback"
    ,{x01:$my_id}
    ,{type:'GET', dataType: 'text', success: function( text) {}}
 );  

我的回调基本上包含以下内容:

DECLARE
    l_my_id NUMBER;

BEGIN 
    l_my_id := TO_NUMBER(apex_application.g_x01);

    package1.my_process_record(l_my_id);
                    
END;

在满足行条件时的每次循环迭代,在执行回调之前,页面项目递增以获得处理的记录数。 在循环结束时我调用 apex.submit:

 apex.submit('DISPLAY_SUCCESS');

调用获取包含已处理记录数的页面项目的进程 - P1_RECORDS_PROCESSED 并使用 apex_application.g_print_success_message 向用户显示一条消息,说明已处理的记录数。

一切正常,但有一个问题 - 很多时候 DISPLAY_SUCCESS 进程在回调之前执行,因此处理的记录计数仅在显示消息后增加。如何确保回调在页面提交之前完成?

也许有更好的方法来处理选定的行?

一种解决方案是在回调函数中调用“show_message”功能。

apex.server.process
 ("process_selected_callback"
    ,{x01:$my_id}
    ,{type:'GET',
      dataType: 'text',
      success: function( text) {
        apex.submit('DISPLAY_SUCCESS');
      }
     }
 );

但缺陷在于,这将始终在处理完成后提交页面,而不管可能发生的任何数据库错误。由于 apex.server.process 不会在数据库错误时触发,而只是监视 AJAX 调用是否已成功执行。

要解决该问题,您可以 return 一个包含实际成功结果的 json 对象。

create or replace package1
  procedure my_process_record
  begin
    apex_json.open_object;

    << place the processing logic here >>

    apex_json.write('success', true);
    apex_json.close_object;
  exception
    when others then
      -- Free all output written so far
      apex_json.free_output;

      -- Create json error object
      apex_json.open_object;
      apex_json.write('success', false);
      apex_json.write('result' , sqlerrm );
      apex_json.close_object;
  end;
end package1;

ajax 调用可以作用于 returned 结果标签

apex.server.process
 ("process_selected_callback"
    ,{x01:$my_id}
    ,{type:'GET',
      dataType: 'json',
      success: function( json) {
        if ( json.hasOwnProperty("success") && json.success == true ) {
          apex.submit('DISPLAY_SUCCESS');
        }
        else {
          //Code to show the error
        }
      }
     }
 );

希望这个,给你一个方向。

有两种方法可以做到这一点。

第一种方法:

使用Javascript 承诺。 Apex 让您轻松自如 apex.server.process returns 一个 Promise 对象。

由于您正在遍历行并为每一行执行回调,因此您可以将每个 apex.server.process 调用返回的 Promise 存储到一个数组中,然后使用 Promise.all() 函数等待所有要解决的 Promise(AJAX 请求完成),然后调用 apex.submit('DISPLAY_SUCCESS');。如果您的任何一个 AJAX 调用可能失败,您可以使用 Promise.allSettled() 而不是 Promise.all()

可以参考这个了解Promise.all()函数 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

第二种方法:

第一种方法似乎效率低下。您真的需要为处理的每一行进行单独的 AJAX 调用,因为看起来您所做的只是将 ID 传递给包函数吗?

为什么不 运行 一个循环并将所有 ID 存储在一个数组中然后执行 JUST ONE AJAX 调用并将数组传递给它?可以通过您的 AJAX PL/SQL 代码完成 ID 的循环,这不仅会更快(大概)而且对于浏览器来说也更有效,因为它不必 运行 通过多个 AJAX 调用和所有相关开销。