首页 > 解决方案 > 如何将动态操作或进程附加到菜单弹出列表项 - APEX 21.1

问题描述

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

在此处输入图像描述

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

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

更新:我继续在此处将其添加为 APEX Idea (FR-2133) 。如果您认为这是值得添加到 APEX 的内容,请给它一个支持。

标签: oracle-apex

解决方案


不幸的是,没有内置的解决方案。John Snyders有一篇很好的博客文章描述了一种自己构建的方法。

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

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

(表 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。我把它变成了一个链接,其目标 URL 为#(我们真的不需要目标)和这些属性:

财产 价值
链接文本 <span class="fa fa-navicon" aria-hidden="true" title="report menu"></span>
链接属性 class="report-menu" data-key="#EMPNO#" data-menu="EMPLOYEE_MENU"

链接文本显示一个合适的图标,属性是它开始工作的原因。该data-key属性定义了该行的主键值,该data-menu属性指定了要使用的 REPORT_MENUS 中的哪一个。

动态动作

我们现在需要一个动态动作来处理点击菜单。这使用 jQuery 选择器.report-menu来识别被点击的链接,并执行以下 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”,该进程返回包含菜单选项的 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>占位符。


推荐阅读