[Из песочницы] Oracle APEX: Interactive Report with Checkboxes

В этой статье описывается процесс создания в среде Oracle APEX страницы c интерактивным отчетом, в котором можно отметить записи для последующей их обработки. Предполагается,
что читатель имеет базовые знания о среде разработки APEX и БД Oracle.
image

Отчет с возможностью отметки отдельных записей для обработки — вещь очень удобная, но к сожалению до сих пор не реализованная «из коробки». В APEX API имеется функция apex_item.checkbox2 которая позволяет показать в отчете чекбоксы, но обрабатывать их приходится программисту. Обработку сильно осложняет то, что в многостраничном отчете чекбоксы существуют только для текущей страницы, и при переходах между страницами отчета значения отмеченных чекбоксов нужно где-то сохранять. В данном случае для этого используется коллекция APEX.

Несколько слов о коллекции APEX. Коллекция APEX — это именованная структура данных, существующая в пределах пользовательской сессии, предназначенная для манипуляций с данными при построении сложных форм ввода данных, мастеров и пр. Коллекция напоминает своей структурой таблицу из 50 атрибутов типа VARCHAR2(4000), 5 атрибутов типа Number, 5 атрибутов типа Date, 1 атрибута типа XML, 1 атрибута типа BLOB и 1 атрибута типа СLOB. Работают с коллекцией через PL/SQL API APEX_COLLECTION.

Итак, на страничке будем использовать такие хитрости и трюки:

  • чекбоксы в отчет добавим при помощи функции apex_item.checkbox2.
  • изменение состояния чекбокса будем обрабатывать при помощи javascript функции, вызываемой из Dynamic Action.
  • сохранять состояние чекбоксов будем в коллекции APEX, для этого будем вызывать AJAX-ом OnDemand процедуру записи в коллекцию.

Будем считать, что у нас уже есть страничка с интерактивным отчетом на базе запроса:
select  id, name, descr  from geo

где id — поле первичного ключа таблицы. Его мы будем передавать в качестве атрибута чекбокса в коллекцию, и его будем использовать при обработке отмеченных записей.

П.1 Создадим процесс на странице:

Create → Page Component → Process →
Process type: PL/SQL code
Name: AJAX_UpdateChBoxCollection
Point: Ajax Callback
PL/SQL Page Process заполняем следующим кодом:

declare
    l_value  varchar2(4000);
    l_seq_id number := 0;
    seq number := 0;
    l_collection_name constant varchar2(30) := 'CHBOXCOLL';
begin
------------------------------------------------------------------
-- Get the value of the global var which was set by JavaScript
------------------------------------------------------------------
l_value := apex_application.g_x01; 
------------------------------------------------------------------------
-- If our collection named doesn't exist yet, create it
------------------------------------------------------------------------
    if apex_collection.collection_exists( l_collection_name ) = FALSE then
       apex_collection.create_collection( p_collection_name => l_collection_name );
    end if;
---------------------------------------------------------------------
-- See if the specified value is already present in the collection
---------------------------------------------------------------------
    for c1 in (select seq_id  
                 from apex_collections  
                where collection_name = l_collection_name  
                  and c001 = l_value) loop
        l_seq_id := c1.seq_id;
        exit;
    end loop;
-------------------------------------------------------------------
-- If the current value was not found in the colleciton, add it. 
-- Otherwise, delete it from the collection.
-------------------------------------------------------------------
--    Htp.Prn('Seq:'||l_seq_id);
    if l_seq_id = 0 then
        begin
            seq := apex_collection.add_member( p_collection_name => l_collection_name,
                                               p_c001            => l_value );
--            Htp.Prn(' Set:'||l_value||' seq_id:'||seq);
        end;  
    else
        begin
            apex_collection.delete_member( p_collection_name => l_collection_name,
                                           p_seq             => l_seq_id );
--            Htp.Prn(' Rst:'||l_value);
        end;    
    end if;
    commit;
end;

Эта процедура создает коллекцию с именем «CHBOXCOLL» если она еще не была создана,
и добавляет/удаляет запись в коллекцию для изменившего состояние чекбокса. Название коллекции везде пишется капсом. Оно должно быть уникальным. В результате в коллекции будут атрибуты отмеченных записей.

П.2 Далее добавим на страницу код javascript функции который будет вызывать этот процесс:

Edit Page → JavaScript → Function and Global Variable Declaration

function ajax_call_func(val) 
   { apex.server.process( "AJAX_UpdateChBoxCollection", 
                         { x01: val}, 
                         { dataType: "text",
                            success: function( pData ) 
                                             { console.log(pData); }  
                           }
                         );
    };

Эта функция вызовет ранее нами созданную функцию с именем «AJAX_UpdateChBoxCollection» и передаст ей значение «val» через глобальную переменную apex_application.g_x01.
Результат типа «text» может быть возвращен из процедуры «AJAX_UpdateChBoxCollection» при 
помощи функции Htp.Prn ('какой-то результат').

П.3 Создадим чекбоксы в отчете, для этого отредактируем запрос следующим образом:

select apex_item.checkbox2(p_idx => 1,
                           p_value => id,
                           p_attributes => 'class="chbox_UpdColl"',
                           p_checked_values => a.c001) cbox,
        id,name,descr
from geo,apex_collections a
 where a.c001 (+)= id
   and a.collection_name (+)= 'CHBOXCOLL'

В данном случае в запрос добавляется колонка на базе функции apex_item.checkbox2,
, а также наша коллекция, связанная с нашей таблицей по id. Коллекция нам нужна лишь для получения состояния чекбокса при первоначальной загрузке страницы и при переходе между страницами отчета. Тип колонки с чекбоксами должен быть «Standart report column».

Коротко опишу используемые параметры apex_item.checkbox2:

p_idx => 1

номер переменной APEX_APPLICATION 1 соответствует F01; 2 — F02 и тп.

p_value => id

значение, которое будем передавать в коллекцию, в данном случае это поле «id» таблицы

p_attributes => 'class=«chbox_UpdColl»'

HTML атрибуты, в данном случае используется тэг class=«chbox_UpdColl» который потом используется в качестве jQuery selector в Dynamic Action.

p_checked_values => a.c001

использует значение из коллекции для указания состояния чекбокса

Для наглядности добавим еще один отчет на базе Sql запроса, который назовем Collecton и который будет показывать нам содержимое коллекции:

select a.seq_id,a.c001
from apex_collections a
 where a.collection_name (+)= 'CHBOXCOLL'

П.4 Создадим Dynamic Action который будет срабатывать по изменению состояния чекбокса и вызывать созданную в П.3 JavaScript функцию:

Event: Change
Selection Type: jQuery Selector
jQuery Selector: .chbox_UpdColl
Condition: none

Action: Execute JavaScript Code
Fire When Event Result Is: True
Fire On Page Load: False
Code:

var
$checkBox = $(this.triggeringElement);
ajax_call_func( $checkBox.val() );

В поле jQuery Selector записывается значение атрибута 'class' из параметров функции apex_item.checkbox2 в П.3. Перед ним нужно обязательно поставить точку.

В созданный Dynamic Action добавим еще одно действие — обновление отчета коллекции после нажатия на чекбокс:

Action: Refresh
Selection Type: Region
Region: Collecton

Функционал чекбоксов уже работает, остается только добавить обработчик отмеченных чекбоксами записей. Пример такого обработчика с последовательным извлечением данных из коллекции при помощи курсора и записью их в файл собираюсь оформить в виде отдельной статьи.

Основная идея почерпнута здесь. Автор сохраняет отмеченные чекбоксы списком в Item на странице.
Недостаток — максимальная длина хранимого списка — 4000 символов. Использование коллекции в нашем случае снимает это ограничение.

Про использование Ajax Callback в APEX хорошо написано здесь.

Код тестировался на сайте apex.oracle.com на Application Express 5.1.0.00.45
Пожелания и конструктивная критика приветствуется.

Комментарии (0)

© Habrahabr.ru