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

如何初始化不显示的子视图?解决首次添加项失效问题

问题描述

我的应用包含两个带列表的视图,分属独立组件。用户点击按钮可将主视图中的项添加到子视图,子视图初始不可见,首次点击按钮时才会显示。

当前问题:首次点击按钮时,项无法添加到子视图,因为子视图尚未完成初始化:

  • 要添加的项通过EventBus传递,子视图控制器在onInit中订阅EventBus
  • 主视图控制器触发导航到子视图后立即发布事件传递数据,但首次事件在子视图初始化完成前就已触发,导致事件未被处理
  • 已尝试在manifest.json中设置"lazy": false,但无效果

需求:

  1. 如何等待子视图初始化完成后再触发EventBus?
  2. 是否有更优的应用设计方案?

应用层级

子视图位于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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 11:14:53