如何将动态操作或流程附加到菜单弹出列表项 - APEX 21.1

How to attatch Dynamic Action or Process to a Menu Popout list item - APEX 21.1

我正在尝试将下拉菜单按钮添加到经典报表行,并将菜单项分配给流程或 DA。我已经使用 Universal Theme 文档来帮助我弄清楚如何将菜单按钮添加到经典报告中,但现在我卡住了,不明白如何 assign/attach 对每个项目进行动态操作或处理在我的菜单列表中:

对于这种情况,两个菜单项都只会打开一个对话框页面,传递行的主键 (MASTER_ID),但其他地方的一些其他操作将需要处理更复杂的逻辑,其中 APEX 处理或DA最好。

我会感到惊讶的是 APEX 没有像这样的东西可以在本地实现,因为交互式网格有类似的东西并且是一种常见的网络模式。

更新:我继续将其添加为 APEX 创意 (FR-2133) here。如果您认为这值得添加到 APEX,请给它一个赞。

很遗憾,没有针对此问题的内置解决方案。有一个 good blog post by John Snyders 描述了一种自己构建它的方法。

我也构建了一些类似的功能,我有一个 demo of here。这使用定制的 table 来存储菜单选项,并在打开菜单时进行 AJAX 调用以获取要显示的适当菜单条目。这些可以是有条件的,例如“计算佣金”菜单条目仅适用于 job='SALESMAN'.

的员工

Tables

create table  report_menus 
   ( menu_name varchar2(30), 
     constraint report_menus_pk primary key (menu_name)
   );

create table  report_menu_entries 
   ( menu_name varchar2(30) not null enable, 
     entry_title varchar2(100) not null enable, 
     entry_target varchar2(1000) not null enable, 
     display_sequence number, 
     condition_type varchar2(30), 
     condition_expression varchar2(4000), 
     constraint report_menu_entries_pk 
        primary key (menu_name, display_sequence),   
     constraint report_menu_entries_fk1 
        foreign key (menu_name)
           references  report_menus (menu_name) 
    );

(Table REPORT_MENUS 是为了完整性,但在这个演示中没有做太多事情)。

示例数据

在我的示例中,我创建了一个名为 'EMPLOYEE_MENU' 的菜单,其中包含 2 个选项:

insert into report_menu_entries values 
   ( 'EMPLOYEE_MENU',
     'Update',
     'f?p=&APP_ALIAS.:3:&SESSION.::&DEBUG.:3:P3_EMPNO:<pk>',
     1,
     'NOT_EXISTS',
     'select * from emp where empno=<pk> and job = 'PRESIDENT''');

insert into report_menu_entries values 
   ( 'EMPLOYEE_MENU',
     'Calculate commission',
     'javascript:alert('Not yet implemented');',
     2,
     'EXISTS',
     'select * from emp where empno=<pk> and job='SALESMAN''');

我发明了一个特殊的占位符 <pk>,无论我想插入我们所在记录的主键(即本演示中的 EMPNO),我都可以使用它。这在目标 URL 和取决于数据的条件中是必需的。

报告地区

在报告中,我通过选择 null as menu 为菜单创建了一个虚拟列。我把它变成一个 Link,目标 URL 为 #(我们真的不需要目标)和这些属性:

Property Value
Link text <span class="fa fa-navicon" aria-hidden="true" title="report menu"></span>
Link attributes class="report-menu" data-key="#EMPNO#" data-menu="EMPLOYEE_MENU"

link 文本显示一个 suitable 图标,其属性使其开始工作。 data-key 属性定义该行的主键值,data-menu 属性指定使用我们的 REPORT_MENUS 中的哪个。

动态动作

我们现在需要一个动态动作来处理菜单上的点击。这使用 jQuery 选择器 .report-menu 来识别被单击的 link,并执行此 Javascript 代码:

showReportMenu (this.triggeringElement);

Javascript代码

showReportMenu是一个Javascript函数,定义如下:

function showReportMenu (pLink) {
    var theLink = $(pLink);
    var dataMenu = theLink.attr("data-menu");
    var dataKey = theLink.attr("data-key");
    apex.server.process ( "Show_Report_Menu", {
        x01: dataMenu,
        x02: dataKey
        }, {
       success: function( pData ) {
           $('div#reportMenu').remove();
            var html = '<div id="reportMenu" ><ul>';
            for (i=0; i<pData.menu.length; i++) {
                if (pData.menu[i].url == '') {
                    html = html + '<li><span>' + pData.menu[i].title + '</span></li>';
                } else {
                    html = html + '<li><a href="' + pData.menu[i].url + '">' + pData.menu[i].title + '</a></li>';
                }
            }
            html = html + '</ul></div>';
            $(theLink).after(html);
            $('#reportMenu').menu({}).menu("toggle",theLink);
       }
    });
}

调用 AJAX 回调应用程序进程 'Show_Report_Menu',其中 returns JSON 包含菜单选项,然后显示。

申请流程

'Show_Report_Menu'进程只是调用了一个过程:

report_menu_pkg.render_menu
  ( p_menu_name => apex_application.g_x01
  , p_keyvals => apex_application.g_x02
  );

程序包代码

该过程查找菜单的菜单项,决定是否应显示键值,并返回要显示的 JSON。它看起来像这样:

procedure render_menu
    ( p_menu_name varchar2
    , p_keyvals   varchar2
    )
is
    l_first boolean := true;
    k_template constant long := '{"title": "%0", "url": "%1"}';
    l_buffer long;
    l_test_sql long;
    l_count integer;
begin
    -- Construct a JSON object to return the menu entries e.g. {"menu": [{"title": "Update", "url": ".."}, {"title": "Delete", "url": "..."}]}
    sys.htp.p('{"menu": [');

    -- Process the menu entries in display sequence order and check any condition before adding to the JSON
    <<entries>>
    for r in (
        select *
        from report_menu_entries
        where menu_name = p_menu_name
        order by display_sequence
    ) loop
        -- Check any condition, substituting placeholder <pk> with the actual key value
        case r.condition_type
            when 'EXISTS' then
                l_test_sql := 'select count(*) from dual where exists (' || replace (r.condition_expression, '<pk>', p_keyvals) || ')';
                execute immediate l_test_sql  into l_count;
                continue entries when l_count = 0;
            when 'NOT_EXISTS' then
                l_test_sql := 'select count(*) from dual where exists (' || replace (r.condition_expression, '<pk>', p_keyvals) || ')';
                execute immediate l_test_sql  into l_count;
                continue entries when l_count = 1;
            else
                null;
        end case;

        -- Separate entries by commas (no comma befor first)
        if l_first then
            l_first := false;
        else
            sys.htp.p (',');
        end if;

        -- Replace placeholders in target URL including the key value
        r.entry_target := replace (r.entry_target, '<pk>', p_keyvals);
        r.entry_target := replace (r.entry_target, '&APP_ALIAS.', v('APP_ALIAS'));
        r.entry_target := replace (r.entry_target, '&SESSION.', v('SESSION'));
        r.entry_target := replace (r.entry_target, '&DEBUG.', v('DEBUG'));
        r.entry_target := apex_util.prepare_url (r.entry_target);
        
        -- Construct JSON entry
        l_buffer := apex_string.format (k_template, r.entry_title, r.entry_target);
        sys.htp.p(l_buffer);
    end loop entries;

    if l_first then
        l_buffer := apex_string.format (k_template, '(No actions available)', null);
        sys.htp.p(l_buffer);
    end if;
    sys.htp.p(']}');
end;

我认为这就是一切。有改进的余地,因为这只是演示代码。理想情况下, JSON 将使用 APEX_JSON 或其他任何方式构建得更健壮,并且它应该能够处理复合键,例如通过传入以逗号分隔的值列表并指定例如<pk1>,<pk2> 作为占位符。