如何在Oracle APEX中实现主从表单一体化展示?
Oracle APEX 主从页面简化:主表单内嵌动态明细行实现
以下是将独立主/明细表单改造为主表单内嵌可动态新增明细行的具体步骤,完全匹配你要的效果:
一、基础准备
- 确保主表表单页面已创建,主表ID(如
P1_MASTER_ID)设为隐藏项:新增时自动生成(可通过序列或触发器),编辑时从主表数据中获取。 - 提前规划明细字段对应的APEX项命名规则,比如用
P1_DETAIL_字段名_索引格式(如P1_DETAIL_PRODUCT_0、P1_DETAIL_QUANTITY_0),方便后续遍历处理。
二、构建内嵌明细行区域
在主表单下方添加一个静态内容区域,插入如下HTML表格(替换字段为你的实际明细列):
<table id="detail-table" border="1" cellpadding="4"> <thead> <tr> <th>产品</th> <th>数量</th> <th>金额</th> <th>操作</th> </tr> </thead> <tbody> <tr id="detail-row_0"> <td><input type="text" id="P1_DETAIL_PRODUCT_0" name="P1_DETAIL_PRODUCT_0" class="apex-item-text"></td> <td><input type="number" id="P1_DETAIL_QUANTITY_0" name="P1_DETAIL_QUANTITY_0" class="apex-item-number"></td> <td><input type="number" id="P1_DETAIL_AMOUNT_0" name="P1_DETAIL_AMOUNT_0" class="apex-item-number" onblur="addDetailRow()"></td> <td><button type="button" onclick="deleteDetailRow(this)">删除</button></td> </tr> </tbody> </table>
注意:给最后一个明细字段(如金额)绑定
onblur事件,实现"填完一行自动新增下一行"的效果。
三、编写JavaScript实现动态行功能
在页面的Function and Global Variable Declaration中添加以下脚本:
// 新增明细行 function addDetailRow() { const table = document.getElementById('detail-table'); const lastRow = table.querySelector('tbody tr:last-child'); const currentIndex = parseInt(lastRow.id.split('_')[1]); const newIndex = currentIndex + 1; // 复制并初始化新行 const newRow = lastRow.cloneNode(true); newRow.id = `detail-row_${newIndex}`; const inputs = newRow.querySelectorAll('input'); inputs.forEach(input => { const oldId = input.id; input.id = oldId.replace(currentIndex, newIndex); input.name = input.id; input.value = ''; // 重新初始化APEX组件,确保验证/交互正常 apex.item(input.id).init(); }); // 给新行的金额字段绑定新增事件 newRow.querySelector('[id$="_AMOUNT_' + newIndex + '"]').setAttribute('onblur', 'addDetailRow()'); table.querySelector('tbody').appendChild(newRow); } // 删除明细行(至少保留1行空白行) function deleteDetailRow(btn) { const table = document.getElementById('detail-table'); if (table.querySelectorAll('tbody tr').length > 1) { btn.closest('tr').remove(); } }
四、提交时批量保存主/明细数据
在页面的Processing区域添加两个PL/SQL处理:
1. 保存主表数据
DECLARE BEGIN -- 新增模式 IF :P1_MASTER_ID IS NULL THEN INSERT INTO MASTER_TABLE (COL1, COL2) -- 替换为主表实际字段 VALUES (:P1_COL1, :P1_COL2) RETURNING MASTER_ID INTO :P1_MASTER_ID; -- 编辑模式 ELSE UPDATE MASTER_TABLE SET COL1 = :P1_COL1, COL2 = :P1_COL2 WHERE MASTER_ID = :P1_MASTER_ID; END IF; END;
2. 保存明细数据
DECLARE l_index NUMBER := 0; l_product VARCHAR2(100); l_quantity NUMBER; l_amount NUMBER; BEGIN -- 编辑模式下先清除旧明细 IF :P1_MASTER_ID IS NOT NULL THEN DELETE FROM DETAIL_TABLE WHERE MASTER_ID = :P1_MASTER_ID; END IF; -- 遍历所有明细行,批量插入 LOOP l_product := apex_util.get_session_state('P1_DETAIL_PRODUCT_' || l_index); l_quantity := apex_util.get_session_state('P1_DETAIL_QUANTITY_' || l_index); l_amount := apex_util.get_session_state('P1_DETAIL_AMOUNT_' || l_index); -- 无数据则停止遍历 IF l_product IS NULL AND l_quantity IS NULL AND l_amount IS NULL THEN EXIT; END IF; INSERT INTO DETAIL_TABLE (MASTER_ID, PRODUCT, QUANTITY, AMOUNT) VALUES (:P1_MASTER_ID, l_product, l_quantity, l_amount); l_index := l_index + 1; END LOOP; END;
五、编辑模式加载已有明细
如果需要支持编辑时回显已有明细,在页面Before Header添加PL/SQL处理:
DECLARE l_index NUMBER := 0; BEGIN IF :P1_MASTER_ID IS NOT NULL THEN -- 遍历已有明细,给对应APEX项赋值 FOR rec IN (SELECT PRODUCT, QUANTITY, AMOUNT FROM DETAIL_TABLE WHERE MASTER_ID = :P1_MASTER_ID) LOOP apex_util.set_session_state('P1_DETAIL_PRODUCT_' || l_index, rec.PRODUCT); apex_util.set_session_state('P1_DETAIL_QUANTITY_' || l_index, rec.QUANTITY); apex_util.set_session_state('P1_DETAIL_AMOUNT_' || l_index, rec.AMOUNT); l_index := l_index + 1; END LOOP; -- 最后新增一行空白行 apex_util.set_session_state('P1_DETAIL_PRODUCT_' || l_index, NULL); END IF; END;
内容的提问来源于stack exchange,提问作者user30044589
相关产品推荐
相关产品推荐

