Oracle APEX - как обеспечить завершение обратного вызова до отправки страницы

У меня есть интерактивная сетка с настраиваемой кнопкой. Кнопка при нажатии обрабатывает выбранные строки:

перебирает все выбранные строки и выполняет обратный вызов для каждой строки, если строка соответствует критерию.

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процесс выполняется перед обратным вызовом, поэтому количество обработанных записей увеличивается только после отображения сообщения. Как я могу гарантировать завершение обратного вызова до отправки страницы?

Может, есть способ лучше обработать выделенные строки?

2 ответа

Решение

Это можно сделать двумя способами.

Первый подход:

Используйте обещания Javascript. Apex упрощает вам задачу, посколькуapex.server.process возвращает Promise объект.

Поскольку вы просматриваете строки и выполняете обратный вызов для каждой строки, вы можете просто сохранить возвращенное обещание из каждого apex.server.process вызовите массив, а затем используйте Promise.all() чтобы дождаться выполнения всех обещаний (запросы 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 для каждой обрабатываемой строки, потому что кажется, что все, что вы делаете, просто передаете идентификатор функции Package?

Почему бы не запустить цикл и не сохранить все идентификаторы в массиве, а затем выполнить ТОЛЬКО ОДИН вызов AJAX и передать ему массив? Цикл по идентификаторам может быть выполнен вашим кодом AJAX PL/SQL, который будет не только быстрее (предположительно), но и более эффективным для браузера, поскольку ему не нужно выполнять несколько вызовов AJAX и все связанные с ними накладные расходы.

Одно из решений - вызвать функцию "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.

Чтобы решить эту проблему, вы можете вернуть объект 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 может воздействовать на возвращаемый тег результата

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

Надеюсь, это и даст вам направление.

Другие вопросы по тегам