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
相关产品推荐
相关产品推荐

