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
}
}
}
);
Надеюсь, это и даст вам направление.