如何将动态操作或流程附加到菜单弹出列表项 - APEX 21.1
How to attatch Dynamic Action or Process to a Menu Popout list item - APEX 21.1
我正在尝试将下拉菜单按钮添加到经典报表行,并将菜单项分配给流程或 DA。我已经使用 Universal Theme 文档来帮助我弄清楚如何将菜单按钮添加到经典报告中,但现在我卡住了,不明白如何 assign/attach 对每个项目进行动态操作或处理在我的菜单列表中:
APPROVE WORKLOAD
ASSIGN WORKLOAD
对于这种情况,两个菜单项都只会打开一个对话框页面,传递行的主键 (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>
作为占位符。
我正在尝试将下拉菜单按钮添加到经典报表行,并将菜单项分配给流程或 DA。我已经使用 Universal Theme 文档来帮助我弄清楚如何将菜单按钮添加到经典报告中,但现在我卡住了,不明白如何 assign/attach 对每个项目进行动态操作或处理在我的菜单列表中:
APPROVE WORKLOAD
ASSIGN WORKLOAD
对于这种情况,两个菜单项都只会打开一个对话框页面,传递行的主键 (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>
作为占位符。