You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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。传递给函数的值硬编码在项模板中,因此每种账户类型(如资产、费用、负债)需对应不同模板,目前我更关注概念验证,后续可优化减少模板数量。

代码P1:静态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 = []) {
    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);
}
代码P2:项模板
<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'])即可。

相关学习链接

内容的提问来源于stack exchange,提问作者bunchesNbunches

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 23:50:55