Oracle APEX静态JS文件中替换字符串失效问题求助
我是Oracle APEX和JavaScript的新手,恳请详细解释代码建议或方案,或提供相关链接帮助我理解思路。非常感谢您的帮助,希望能一次理解无需再次请教。
我尝试使用静态JS应用文件提供可跨应用复用的函数,该需求需用到替换字符串,但通过静态文件链接引入时,替换字符串未被替换。函数可正常访问,说明链接有效,但应用未填充必要的替换值。若将JS代码直接放在页面静态区域的HTML代码段中,可得到预期结果。我更倾向于使用静态应用文件功能,便于源码维护,无需将代码存储在应用/页面内。
为便于理解,以下说明我的目标及原因:我正在将现有Oracle Forms 11g应用迁移至Oracle APEX。现有应用常提供搜索/查找界面,允许用户输入多种参数缩小范围。这些查找界面通过LOV(KEY-LIST-VALUES)触发的字段关联,退出时设置全局变量,返回时读取全局变量。例如,:global.account_type := 'EXPENSE';用于用户为系统设置部分分配GL账户的场景,该字段要求账户为费用类,查找界面检测到全局变量设置后,会自动设置并限制搜索参数。
在APEX中实现该功能,我通过应用计算定义了应用项&GL_FIND_APP_ID和&GL_FIND_PAGE_ID,值分别为102和5。这些应用项用于JS函数,在KeyDown事件触发时构建URL。传递给函数的值硬编码在项模板中,因此每种账户类型(如资产、费用、负债)需对应不同模板,目前我更关注概念验证,后续可优化减少模板数量。
function buildFieldTargets(pPage, pFields = []) { var vReturn = "" console.log('pPage: ' + pPage); for (i in pFields) { vReturn += ",P" + pPage + "_" + pFields[i]; } vReturn = vReturn.substring(1); console.log('fieldString: ' + vReturn); return vReturn; } function buildValueTargets(pValues = []) { var vReturn = "" for (v in pValues) { vReturn += "," + pValues[v]; } vReturn = vReturn.substring(1) console.log('valueString: ' + vReturn); return vReturn; } function prepareURL(pUrl, pPage, pFields = [], pValues = []) { var vReturn = pUrl //Fields in auto-generated string are always forced to lower case vReturn = vReturn.replace('field_target', buildFieldTargets(pPage, pFields)); vReturn = vReturn.replace('VALUE_TARGET', buildValueTargets(pValues)); return vReturn } function lookUpGL(pFields = [], pValues = []) { var vUrl = "f?p=&GL_FIND_APP_ID.:&GL_FIND_PAGE_ID.:&APP_SESSION.:::&GL_FIND_PAGE_ID.:field_target:VALUE_TARGET"; var vPage = '&GL_FIND_PAGE_ID.' console.log('Default URL: ' + vUrl); vUrl = prepareURL(vUrl, vPage, pFields, pValues); console.log('Prepared URL: ' + vUrl); apex.navigation.redirect(vUrl); }
<script> document.addEventListener("keydown", function(e) { console.log('KeyDown Event Triggered'); if (e.code == "F9") { console.log('F9 was hit.'); document.getElementById(e.target.id + 'LOV').click(); } }); </script> <a id= "#CURRENT_ITEM_NAME#LOV" href="javascript: lookUpGL(['ACCOUNT_TYPE'], ['EXPENSE'])" ... </a>
不使用静态应用文件链接时功能正常:
使用静态应用文件链接时功能失效:可看到自动生成的URL未触发,原因是替换字符串未被填充。
Oracle APEX的替换字符串(如&GL_FIND_APP_ID.、&APP_SESSION.)只有在APEX页面渲染阶段才会被解析替换为实际值。静态JS文件是浏览器直接从服务器加载的静态资源,APEX不会对其内容做任何解析处理,因此这些替换字符串会原封不动保留在JS代码中,导致生成的URL无效。
而将JS代码放在页面静态区域时,APEX会先替换掉所有变量再把代码输出给浏览器,所以功能正常。
以下两种方案都能让你继续使用静态JS文件,同时正确获取APEX应用项的值:
方案1:将应用项作为参数传递给JS函数
修改静态JS中的lookUpGL函数,让它接收应用ID、页面ID参数;在项模板调用函数时,传入APEX替换后的实际值。
修改后的静态JS代码
function buildFieldTargets(pPage, pFields = []) { var vReturn = "" console.log('pPage: ' + pPage); for (i in pFields) { vReturn += ",P" + pPage + "_" + pFields[i]; } vReturn = vReturn.substring(1); console.log('fieldString: ' + vReturn); return vReturn; } function buildValueTargets(pValues = []) { var vReturn = "" for (v in pValues) { vReturn += "," + pValues[v]; } vReturn = vReturn.substring(1) console.log('valueString: ' + vReturn); return vReturn; } function prepareURL(pUrl, pPage, pFields = [], pValues = []) { var vReturn = pUrl //Fields in auto-generated string are always forced to lower case vReturn = vReturn.replace('field_target', buildFieldTargets(pPage, pFields)); vReturn = vReturn.replace('VALUE_TARGET', buildValueTargets(pValues)); return vReturn } // 新增两个参数接收应用ID和页面ID function lookUpGL(pFindAppId, pFindPageId, pFields = [], pValues = []) { // 使用APEX内置全局变量获取会话ID,替代&APP_SESSION. var vUrl = `f?p=${pFindAppId}:${pFindPageId}:${apex.gInstance.sessionId}:::${pFindPageId}:field_target:VALUE_TARGET`; var vPage = pFindPageId; console.log('Default URL: ' + vUrl); vUrl = prepareURL(vUrl, vPage, pFields, pValues); console.log('Prepared URL: ' + vUrl); apex.navigation.redirect(vUrl); }
修改后的项模板代码
<script> document.addEventListener("keydown", function(e) { console.log('KeyDown Event Triggered'); if (e.code == "F9") { console.log('F9 was hit.'); document.getElementById(e.target.id + 'LOV').click(); } }); </script> <!-- 传入APEX替换后的应用ID和页面ID --> <a id= "#CURRENT_ITEM_NAME#LOV" href="javascript: lookUpGL(&GL_FIND_APP_ID., &GL_FIND_PAGE_ID., ['ACCOUNT_TYPE'], ['EXPENSE'])" ... </a>
方案2:将应用项存储在页面全局变量中
在页面静态区域添加脚本,把APEX应用项的值存入全局变量;静态JS直接读取这些变量。
步骤1:在页面静态区域定义全局变量
<script> // 全局变量存储APEX应用项配置 window.GL_FIND_CONFIG = { appId: &GL_FIND_APP_ID., pageId: &GL_FIND_PAGE_ID. }; </script>
步骤2:修改静态JS代码
function buildFieldTargets(pPage, pFields = []) { var vReturn = "" console.log('pPage: ' + pPage); for (i in pFields) { vReturn += ",P" + pPage + "_" + pFields[i]; } vReturn = vReturn.substring(1); console.log('fieldString: ' + vReturn); return vReturn; } function buildValueTargets(pValues = []) { var vReturn = "" for (v in pValues) { vReturn += "," + pValues[v]; } vReturn = vReturn.substring(1) console.log('valueString: ' + vReturn); return vReturn; } function prepareURL(pUrl, pPage, pFields = [], pValues = []) { var vReturn = pUrl //Fields in auto-generated string are always forced to lower case vReturn = vReturn.replace('field_target', buildFieldTargets(pPage, pFields)); vReturn = vReturn.replace('VALUE_TARGET', buildValueTargets(pValues)); return vReturn } function lookUpGL(pFields = [], pValues = []) { // 读取全局变量中的配置值 const { appId, pageId } = window.GL_FIND_CONFIG; var vUrl = `f?p=${appId}:${pageId}:${apex.gInstance.sessionId}:::${pageId}:field_target:VALUE_TARGET`; var vPage = pageId; console.log('Default URL: ' + vUrl); vUrl = prepareURL(vUrl, vPage, pFields, pValues); console.log('Prepared URL: ' + vUrl); apex.navigation.redirect(vUrl); }
步骤3:项模板代码保持不变
继续使用原调用方式:lookUpGL(['ACCOUNT_TYPE'], ['EXPENSE'])即可。
- Oracle APEX 应用项官方文档:了解应用项的作用与使用方式
- Oracle APEX 静态文件官方文档:理解静态文件的加载机制
- Oracle APEX JavaScript API 文档:学习
apex.gInstance、apex.navigation等内置JS API
内容的提问来源于stack exchange,提问作者bunchesNbunches

