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

ServiceNow门户内嵌Widget执行c.server.update()丢失初始参数问题

ServiceNow内嵌Widget刷新丢失参数问题解决

我在基于AngularJS的ServiceNow门户中,将my-items widget嵌入自定义widget内,实现代码如下:

父Widget实现代码

服务器脚本

data.widget = $sp.getWidget('my-items', options);

HTML代码

<sp-widget widget="data.widget"></sp-widget>

遇到的问题:当内嵌的my-items widget执行自身的c.server.update()(通过自带的c.asyncGet()函数)时,初始传入的options参数会丢失,导致数据加载异常。

内嵌Widget相关代码

c.asyncGet()客户端函数

c.asyncGet = function() {
    c.data.action = "loadData";
    c.server.update().then(function(response) {
        fetchMyItemsData();
        if (c.data.card_behaviour == 'single') {
            resetCarousel();
        } else {
            adaptCardGrid();
        }
        handleTextOnlyZoom();
    });
};

服务器脚本

(function() {

    data.load_config = options.load_config;
    if (data.load_config === "async" && !input)
        return;
    data.card_behaviour = options.card_behaviour;

    try {
        data.recordLimit = options.list_view_count;
        data.showViewDetails = options.show_view_details;
        data.showIcons = options.show_icons;
        var activityConfigUtil = new sn_ex_sp.ActivityConfigurationUtil();
        data.activityDetails = activityConfigUtil.getActivityData(data.recordLimit);
        //Map actions with associated card
        for (var cardDataIndex = 0; cardDataIndex < data.activityDetails.listViewData.length; cardDataIndex++) {
            var currCardData = data.activityDetails.listViewData[cardDataIndex];
            currCardData.title = currCardData.title ? GlideStringUtil.unEscapeHTML(currCardData.title) : "";
            currCardData.description = currCardData.description ? GlideStringUtil.unEscapeHTML(currCardData.description) : "";
            currCardData.field1Value = currCardData.field1Value ? GlideStringUtil.unEscapeHTML(currCardData.field1Value) : "";
            currCardData.field2Value = currCardData.field2Value ? GlideStringUtil.unEscapeHTML(currCardData.field2Value) : "";
            if (currCardData.actionsWidgetDetail) {
                var context = currCardData.actionsWidgetDetail.parentRecordSysId;

                var actionsWidget = $sp.getWidget("action-widget", {
                    table: currCardData.actionsWidgetDetail.parentTable,
                    context: context,
                    action_group: currCardData.actionsWidgetDetail.actionGrpSysId,
                    max_button_count: 2,
                    primary_colored_button: true,
                    more_icon: 'fa-ellipsis-v'
                });

                currCardData.actionsWidget = actionsWidget;
                currCardData.actionsContext = context;
                currCardData.isActionWidgetVisible = true;
            }
        }

        data.title = gs.getMessage("My active items");

        if (data.activityDetails.listViewData && data.activityDetails.listViewData.length > 0) {

            var isSessionLangGerman = gs.getSession().getLanguage() == "de";
            var itemName = data.activityDetails.primaryCountData.length > 0 ? data.activityDetails.primaryCountData[0].itemName : undefined;
            //Nouns always start with capital letter in German
            itemName = isSessionLangGerman ? itemName : itemName.toLowerCase();

            data.listCountSummary = gs.getMessage("Showing {0} of {1} {2}",
                [data.activityDetails.listViewData.length.toString(),
                    data.activityDetails.primaryCountData[0].itemCount.toString(), itemName
                ]);
            data.noOfCards = data.activityDetails.listViewData.length;
        }
        data.hideWidget = false;
        return data;
    } catch (e) {
        data.hideWidget = true;
        gs.addErrorMessage(gs.getMessage("Error in loading the My Items widget"));
        return data;
    }

})();

我曾尝试从父widget重新初始化内嵌widget来替代调用c.asyncGet(),此时数据已刷新,但视图并未重新渲染——即使console.log()显示数据正确,调用$apply()也无效。


解决方法

这不是sp-widget指令的缺陷,而是因为c.server.update()触发的服务器脚本调用中,options对象仅在widget初始化时传递,后续AJAX请求不会自动携带初始参数。可通过以下两种方式解决:

方法1:在内嵌Widget中保存并传递初始参数

修改my-items的客户端脚本,初始化时保存options,后续调用server.update()时传入:

// 初始化阶段深拷贝保存options,避免引用问题
c.savedOptions = JSON.parse(JSON.stringify(c.options));

c.asyncGet = function() {
    c.data.action = "loadData";
    // 将保存的参数传入update请求
    c.server.update({
        savedOptions: c.savedOptions
    }).then(function(response) {
        fetchMyItemsData();
        if (c.data.card_behaviour == 'single') {
            resetCarousel();
        } else {
            adaptCardGrid();
        }
        handleTextOnlyZoom();
    });
};

修改my-items的服务器脚本,优先从input.savedOptions获取参数,无则使用初始options:

(function() {
    // 优先取请求传递的参数,否则用初始options
    var widgetOptions = input && input.savedOptions ? input.savedOptions : options;

    data.load_config = widgetOptions.load_config;
    if (data.load_config === "async" && !input)
        return;
    data.card_behaviour = widgetOptions.card_behaviour;

    try {
        data.recordLimit = widgetOptions.list_view_count;
        data.showViewDetails = widgetOptions.show_view_details;
        data.showIcons = widgetOptions.show_icons;
        // 后续原有代码保持不变
    } catch (e) {
        // 原有异常处理代码保持不变
    }
})();

方法2:从父Widget控制刷新并强制视图更新

若不想修改内嵌widget代码,可在父widget中重新生成widget实例并触发视图渲染:

父Widget客户端脚本添加刷新函数:

c.refreshMyItems = function() {
    // 请求服务器重新生成widget实例
    c.server.get({
        action: "refresh_widget"
    }).then(function(response) {
        data.widget = response.widget;
        // 用$timeout触发Angular脏检查,强制视图更新
        $timeout(function() {});
    });
};

父Widget服务器脚本添加对应处理:

if (input && input.action === "refresh_widget") {
    data.widget = $sp.getWidget('my-items', options);
} else {
    data.widget = $sp.getWidget('my-items', options);
}

调用c.refreshMyItems()即可完成带正确参数的widget刷新,同时触发视图重新渲染。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 22:24:55