如何初始化不显示的子视图?解决首次添加项失效问题
问题描述
我的应用包含两个带列表的视图,分属独立组件。用户点击按钮可将主视图中的项添加到子视图,子视图初始不可见,首次点击按钮时才会显示。
当前问题:首次点击按钮时,项无法添加到子视图,因为子视图尚未完成初始化:
- 要添加的项通过EventBus传递,子视图控制器在
onInit中订阅EventBus - 主视图控制器触发导航到子视图后立即发布事件传递数据,但首次事件在子视图初始化完成前就已触发,导致事件未被处理
- 已尝试在manifest.json中设置
"lazy": false,但无效果
需求:
- 如何等待子视图初始化完成后再触发EventBus?
- 是否有更优的应用设计方案?
应用层级
子视图位于ShoppingCart组件中。
相关代码
manifest.json
{ [...] "componentUsages": { "ShoppingCart": { "name": "zapp.ShoppingCart", "lazy": false, "settings": {}, "componentData": {} } }, [...] "extends": { "extensions": { "sap.ui.viewExtensions": { "sap.ui.controllerExtensions": { "sap.suite.ui.generic.template.ListReport.view.ListReport": { "controllerName": "zapp.ext.controller.ListReportExt", "sap.ui.generic.app": { "ZC_MODEL": { "EntitySet": "ZC_MODEL" } } } } } } }, "sap.ui.generic.app": { "_version": "1.3.0", "settings": { "forceGlobalRefresh": false, "objectPageHeaderType": "Dynamic", "considerAnalyticalParameters": true, "showDraftToggle": false, "flexibleColumnLayout": { "defaultTwoColumnLayoutType": "TwoColumnsBeginExpanded", "defaultThreeColumnLayoutType": "ThreeColumnsEndExpanded" } }, "pages": { "ListReport|ZC_ARTICLE_": { "entitySet": "ZC_ARTICLE_", "component": { "name": "sap.suite.ui.generic.template.ListReport", "list": true, "settings": { "condensedTableLayout": true, "smartVariantManagement": true, "enableTableFilterInPageVariant": true } }, "pages": { "ObjectPage|ZC_ARTICLE_": { "entitySet": "ZC_ARTICLE_", "defaultLayoutType": "MidColumnFullScreen", "component": { "name": "sap.suite.ui.generic.template.ObjectPage" } }, "CartCanvas": { "component": { "name": "sap.suite.ui.generic.template.Canvas", "settings": {} }, "implementingComponent": { "componentUsage": "ShoppingCart", "settings": {} }, "routingSpec": { "noOData": true, "noKey": true, "routeName": "toShoppingCart" } } } } } }, }
主应用Component.js
sap.ui.define([ "sap/suite/ui/generic/template/lib/AppComponent" ], function (Component) { "use strict"; return Component.extend("zapp.Component", { metadata: { manifest: "json" }, }); });
主视图扩展控制器 ListReportExt.controller.js
sap.ui.define([ "sap/m/MessageToast" ], function(MessageToast) { 'use strict'; return { onAddToCart: function(oEvent) { var oApi = this.extensionAPI; var oNavigationController = oApi.getNavigationController(); oNavigationController.navigateInternal("",{ routeName: "toShoppingCart", isAbsolute: true }); var oArticle = oEvent.getSource().getBindingContext().getObject(); var oEventBus = sap.ui.getCore().getEventBus(); oEventBus.publish("ShoppingCart", "AddToCart", oArticle); MessageToast.show(oArticle.Product + " ajouté au panier"); },
ShoppingCart组件Component.js
sap.ui.define([ "sap/ui/core/UIComponent", "sap/suite/ui/generic/template/extensionAPI/ReuseComponentSupport", "zapp/ShoppingCart/model/ShoppingCart" ], function(UIComponent, ReuseComponentSupport, ShoppingCartModel) { "use strict"; return UIComponent.extend("zapp.ShoppingCart.Component", { metadata: { manifest: "json" }, init: function() { ReuseComponentSupport.mixInto(this, "ShoppingCart"); (UIComponent.prototype.init || jQuery.noop).apply(this, arguments); var oModel = new ShoppingCartModel({cartEntries: {}}); //var oModel = this.getOwnerComponent().getModel("ShoppingCartModel"); this.setModel(oModel); } }); });
ShoppingCart视图控制器 ShoppingCart.controller.js
sap.ui.define([ "sap/ui/core/mvc/Controller", "sap/m/MessageToast" ], function(Controller, MessageToast) { 'use strict'; return Controller.extend("zapp.ShoppingCart.controller.ShoppingCart", { onInit: function() { sap.ui.getCore().getEventBus().subscribe("ShoppingCart", "AddToCart", this.onAddToCart, this); }, onAddToCart: function (sChanel, sEvent, oArticle) { this.getView().getModel().addToCart(oArticle); }, onCreateSalesOrder: function() { MessageToast.show("Commande créée"); } }); });
解决方案
方案1:等待导航完成后操作子组件
导航是异步操作,不能在navigateInternal后立即发布事件。可利用导航返回的Promise,在导航完成后获取已初始化的子组件实例,直接调用模型方法:
修改主视图扩展控制器
onAddToCart: function(oEvent) { var oApi = this.extensionAPI; var oNavigationController = oApi.getNavigationController(); var oArticle = oEvent.getSource().getBindingContext().getObject(); // 导航完成后执行回调 oNavigationController.navigateInternal("",{ routeName: "toShoppingCart", isAbsolute: true }).then(function() { // 获取已初始化的ShoppingCart组件 var oShoppingCartComponent = oApi.getComponent().getComponentUsages().get("ShoppingCart").getInstance(); if (oShoppingCartComponent) { // 直接调用模型方法,无需EventBus oShoppingCartComponent.getModel().addToCart(oArticle); } }); MessageToast.show(oArticle.Product + " ajouté au panier"); }
方案2:改用全局共享模型(更优设计)
购物车属于全局状态,使用全局共享模型替代EventBus是更合理的方案,避免事件时序问题:
步骤1:在主应用manifest.json配置全局模型
"models": { "ShoppingCartModel": { "type": "zapp.ShoppingCart.model.ShoppingCart", "settings": { "cartEntries": {} } } }
步骤2:修改ShoppingCart组件使用全局模型
// ShoppingCart/Component.js init: function() { ReuseComponentSupport.mixInto(this, "ShoppingCart"); (UIComponent.prototype.init || jQuery.noop).apply(this, arguments); // 直接使用主应用的全局模型 var oModel = this.getOwnerComponent().getModel("ShoppingCartModel"); this.setModel(oModel); }
步骤3:主视图控制器直接操作全局模型
// ListReportExt.controller.js onAddToCart: function(oEvent) { var oApi = this.extensionAPI; var oNavigationController = oApi.getNavigationController(); var oArticle = oEvent.getSource().getBindingContext().getObject(); // 直接操作全局购物车模型 oApi.getComponent().getModel("ShoppingCartModel").addToCart(oArticle); // 导航到购物车视图 oNavigationController.navigateInternal("",{ routeName: "toShoppingCart", isAbsolute: true }); MessageToast.show(oArticle.Product + " ajouté au panier"); }
步骤4:移除ShoppingCart控制器的EventBus订阅
// ShoppingCart.controller.js onInit: function() { // 删除EventBus订阅代码 }
方案3:调整EventBus订阅时机(临时方案)
如果必须保留EventBus,可将订阅时机改为视图渲染完成后,确保订阅在事件发布前完成:
修改ShoppingCart控制器
onAfterRendering: function() { sap.ui.getCore().getEventBus().subscribe("ShoppingCart", "AddToCart", this.onAddToCart, this); }, onExit: function() { // 避免重复订阅,在视图销毁时取消订阅 sap.ui.getCore().getEventBus().unsubscribe("ShoppingCart", "AddToCart", this.onAddToCart, this); }
内容的提问来源于stack exchange,提问作者Cutter
相关产品推荐
相关产品推荐

