【问题标题】:Unable to access model from core in sapUI5无法从 sapUI5 中的核心访问模型
【发布时间】:2015-12-08 19:31:39
【问题描述】:

跟进相关问题 here

无论出于何种原因,当我通过 sap.ui.getCore().setModel() 设置模型时,我都无法在我的 xml 视图中访问它。如果我在 this.getView() 上设置它,我完全没有问题。

我的视图 XML

<mvc:View controllerName="ca.toronto.rcsmls.webapp.controller.Login"
xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" xmlns:l="sap.ui.layout">

<Page title="{i18n>loginPageTitle}">
    <content>

        <Panel id="loginPanel" busyIndicatorDelay="0"
            headerText="{i18n>loginPanelTitle}" class="sapUiResponsiveMargin loginPanel"
            width="auto">
            <l:VerticalLayout width="100%">


                <Input type="Text" placeholder="{i18n>loginUidHolder}" value="{/mlsUser/uid}" />

                <Input type="Password" placeholder="{app>/Password}"
                    value="{/mlsUser/password}" />

                <Button text="{i18n>loginButtonText}" press="doLogin"
                    class="sapUiSmallMarginEnd customBold" width="100%" />


            </l:VerticalLayout>
        </Panel>

    </content>
</Page></mvc:View>

我的控制器 JS 包含这个用于 setModel()

 onInit : function() {
        sap.ui.getCore().setModel(new sap.ui.model.json.JSONModel("webapp/controller/app.json"), "app");
    }

再次,如果我将模型设置为 this.getView().setModel() 而不是 getCore() XML 和控制器可以很好地协同工作。我还在 index.html 中添加了 data-sap-ui-xx-bindingSyntax="complex" ,但这似乎并没有什么不同。任何帮助将不胜感激。

已编辑以包含更多信息

我的组件.js

sap.ui.define([
   "sap/ui/core/UIComponent",
   "sap/ui/model/json/JSONModel",
], function (UIComponent, JSONModel) {
   "use strict";
   return UIComponent.extend("ca.toronto.rcsmls.webapp.Component", {
      metadata : {
          manifest: "json"
      },
      init : function () {
         // call the init function of the parent
         UIComponent.prototype.init.apply(this, arguments);
         // set data model
         var oData = {
            mlsUser : {
               uid : "",
               password : "",
            }
         };
         var oModel = new JSONModel(oData);
         this.setModel(oModel);

         // create the views based on the url/hash
         this.getRouter().initialize();
      }
   });
});

我的 manifest.json

{
    "_version": "1.1.0",
    "sap.app": 
    {
        "_version": "1.1.0",
        "id": "ca.toronto.rcsmls",
        "type": "application",
        "i18n": "i18n/i18n.properties",
        "title": "{{appTitle}}",
        "description": "{{appDescription}}",
        "applicationVersion": 
        {
            "version": "1.0.0"
        },

        "ach": "CA-UI5-DOC"
    },

    "sap.ui": 
    {
        "_version": "1.1.0",
        "technology": "UI5",
        "deviceTypes": 
        {
            "desktop": true,
            "tablet": true,
            "phone": true
        },

        "supportedThemes": 
        [
            "sap_bluecrystal"
        ]
    },

    "sap.ui5": 
    {
        "_version": "1.1.0",
        "rootView": "ca.toronto.rcsmls.webapp.view.App",
        "dependencies": 
        {
            "minUI5Version": "1.30",
            "libs": 
            {
                "sap.m": 
                {

                }
            }
        },

        "config": 
        {
            "authenticationService": "http://172.21.226.138:9080/RcsMlsSvc/jaxrs/user/authenticate/",
            "assignedWorkService": "http://172.21.226.138:9080/RcsMlsSvc/jaxrs/mls/searchAssignedWork"
        },

        "models": 
        {
            "i18n": 
            {
                "type": "sap.ui.model.resource.ResourceModel",
                "settings": 
                {
                    "bundleName": "ca.toronto.rcsmls.webapp.i18n.i18n"
                }
            }
        },

        "routing": 
        {
            "config": 
            {
                "routerClass": "sap.m.routing.Router",
                "viewType": "XML",
                "viewPath": "ca.toronto.rcsmls.webapp.view",
                "controlId": "root",
                "controlAggregation": "pages"
            },

            "routes": 
            [
                {
                    "pattern": "",
                    "name": "login",
                    "target": "login"
                },
                {
                    "pattern": "work",
                    "name": "work",
                    "target": "work"
                }
            ],

            "targets": {
                "login": {
                    "viewName": "Login"
                },
                "work": {
                    "viewName": "Work"
                }
            }
        },

        "resources": 
        {
            "css": 
            [
                {
                    "uri": "css/style.css"
                }
            ]
        }
    }
}

模型 app.json

{
    "BaseURL": "https://smp-pNNNNNNtrial.hanatrial.ondemand.com",
    "ES1Root": "https://sapes1.sapdevcenter.com",
    "AppName": "qmacro.myfirst",
    "Username": "yourusername",
    "Password": "yourpassword"
}

我发现了一个核心绑定工作的示例here。这是一个简单得多的应用程序。我仍在试图弄清楚这个项目和我的项目之间有什么区别

【问题讨论】:

    标签: model-view-controller sapui5


    【解决方案1】:

    Github 上的一个类似问题让我知道了这个问题

    默认情况下,UI5 组件不会从其环境(它们所在的ComponentContainer)继承模型和绑定上下文。这样做是为了隔离。

    您可以通过为容器设置属性propagateModel:true 来更改该默认行为:

    new sap.ui.core.ComponentContainer({
      name: "ca.toronto.rcsmls.webapp.Component",
      propagateModel: true
    }).placeAt("content");
    

    propagateModel 的文档可以在API reference 以及 UI5 developer guide 中找到(后一页中的相应段落是最近才添加的,当您提出问题时它不可用)。

    但是当模型是在组件的范围内创建的,并且应该在组件内部使用时,那么应该不需要将它添加到Core中。只需将其分配给组件以在该组件内的视图之间共享它:

    从视图控制器中的某个方法分配它

    onInit : function() {
        this.getOwnerComponent().setModel(
            new sap.ui.model.json.JSONModel(
                "webapp/controller/app.json"), "app");
    }
    

    或在 Component.js 本身的初始化期间

    init : function() {
        // create and set model to make it available to all views
        this.setModel(
            new sap.ui.model.json.JSONModel(
                "webapp/controller/app.json"), "app");
    
        // never forget to call init of the base class
        UIComponent.init.apply(this, arguments);
    }
    

    最现代的方法是在 manifest.json 中配置模型并让框架实例化一个分配它。示例见Walkthrough Tutorial - Step 10: Descriptor for Applications

    使用这些方法中的任何一种,甚至都不需要在另一个视图中读取和设置模型,只要该视图是组件的后代(createContent 返回的控制树的一部分)。

    【讨论】:

    • 您能否澄清一下但是当模型在组件内部创建并在组件内部使用时[...]?我将代码添加到 Component.js 但在我看来我仍然无法使用"{app&gt;/property}" 访问它。 (this.getOwnerComponent() 不是函数
    • 代码 sn-p 旨在用于希望与其他视图(视图控制器)共享模型的视图控制器。如果您想在 Component.js 本身中创建模型,它看起来会略有不同。我更新了我的帖子以澄清差异。
    【解决方案2】:

    我遇到了同样的行为。 如果我创建一个简单的单文件应用程序,没有任何复杂的 UI 元素,那么基于内核的绑定就像一个魅力。

    如果我创建一个复杂的容器,比如一个带有外壳的应用程序,这种绑定将不再起作用。似乎这些容器从视图中隐藏了全局模型。

    作为一种解决方法,我使用了以下代码 sn-p:

    this.getView().setModel(sap.ui.getCore().getModel(modelName), "modelName");
    

    甚至你可以将模型直接绑定到你想使用的控件上。

    如果您必须在多个视图/控件中使用全局模型,它们都不是最佳解决方案,但这对我有用。

    【讨论】:

    • 您能否提供一个不适合您的完整示例?如果它不起作用,我相信这是一个错误!我用一个工作示例扩展了我的答案,以证明使用 Core 中的命名模型绝对没问题。除非被自己的代码“隐藏”,否则没有人会隐藏全局模型。
    【解决方案3】:

    我上面的视图只有密码字段的占位符正在使用您的应用模型。如果此占位符未正确填充,那么我猜无法加载 json 文件,或者内容与您在视图中为密码字段的占位符属性使用的绑定路径不匹配。要了解更多信息,请同时发布您的 json 文件的内容。它应该看起来像这样:

    { "Password" : "Enter your password", ... }
    

    因此根据视图中的绑定,数据对象的根级别必须有“密码”属性。

    您可以在下面找到一个可以帮助您的运行示例。如您所见,它的工作原理就像一个魅力,因此您可以轻松地将命名模型放到核心上并在您的视图中引用它。

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>SAPUI5 single file template | nabisoft</title>
            <script src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
                id="sap-ui-bootstrap"
                data-sap-ui-theme="sap_bluecrystal"
                data-sap-ui-libs="sap.m"
                data-sap-ui-bindingSyntax="complex"
                data-sap-ui-compatVersion="edge"
                data-sap-ui-preload="async"></script>
                <!-- use "sync" or change the code below if you have issues -->
    
            <!-- XMLView -->
            <script id="myXmlView" type="ui5/xmlview">
                <mvc:View
                    controllerName="MyController"
                    xmlns="sap.m"
                    xmlns:core="sap.ui.core"
                    xmlns:l="sap.ui.layout"
                    xmlns:mvc="sap.ui.core.mvc">
                    <App>
                        <Page title="My Page Title">
                            <content>
                                <Panel id="loginPanel" busyIndicatorDelay="0"
                                    headerText="My Login Panel Title" class="sapUiResponsiveMargin loginPanel"
                                    width="auto">
                                    <l:VerticalLayout width="100%">
    
                                        <Input type="Text" placeholder="{Enter User ID}" value="{/mlsUser/uid}" />
    
                                        <Input type="Password" placeholder="{app>/Password}" value="{/mlsUser/password}" />
    
                                        <Button text="{Login}" press="doLogin" class="sapUiSmallMarginEnd customBold" width="100%" />
    
                                    </l:VerticalLayout>
                                </Panel>
                            </content>
                        </Page>
                    </App>
                </mvc:View>
            </script>
    
            <script>
                sap.ui.getCore().attachInit(function () {
                    "use strict";
    
                    //### Controller ###
                    sap.ui.controller("MyController", {
                        onInit : function () {
                            var oData, oModel;
    
                            // 1. app model is only used for the placeholder field in the view
                            oData = {
                                Password : "Enter your password"
                            };
                            oModel = new sap.ui.model.json.JSONModel(oData);
                            sap.ui.getCore().setModel(oModel, "app");
    
                            // 2. default model is used in the view as well
                            oData = {
                                mlsUser : {},
                                Login : "Login now"
                            };
                            oModel = new sap.ui.model.json.JSONModel(oData);
                            sap.ui.getCore().setModel(oModel);
    
                            // 3. we need this because of the relative binding
                            //    of the text property of the login button
                            this.getView().bindElement("/");
    
                        }
                    });
    
                    //### THE APP: place the XMLView somewhere into DOM ###
                    sap.ui.xmlview({
                        viewContent : jQuery("#myXmlView").html()
                    }).placeAt("content");
    
                });
            </script>
    
        </head>
    
        <body class="sapUiBody">
            <div id="content"></div>
        </body>
    </html>

    在这个帖子中,有些人提到“sap.ui.getCore() 适用于小东西,但无论出于何种原因,不适用于更复杂的应用程序”。

    @Marc 还发布了right link to the API docs,您可以在其中找到以下内容:

    ManagedObject 仅在它是 UIArea 的后代

    当然,您必须知道这意味着什么才能编写符合您期望的代码。这里有一个小例子,告诉你如果你有一个小的“误解”会发生什么(见下文)。

    下面的代码创建了两个 sap.m.Text 实例,并将它们的文本属性绑定到一个 JSONModel,它可以作为命名模型“core”直接在 Core 上使用(使用 sap.ui.getCore() 检索)。有 2 个按钮,每个 sap.m.Text 实例一个。在按钮的相应按下处理程序中,我只显示相应 sap.m.Text 实例的 text 属性。如您所见,两个 sap.m.Text 实例都绑定到 JSONModel 中的相同属性。但是,只有第二个 sap.m.Text 被添加到 DOM。

    现在有趣的部分可能与这个线程的混乱有关: 只有第二个 sap.m.Text 控件的 text 属性包含来自 JSONModel 的预期文本“Hello World”。第一个 sap.m.Text 控件的 text 属性没有模型中的值“Hello World”!这是 SAPUI5 的预期行为,并且已记录在案!因此,我想如果您在自己的“复杂”应用程序中遇到类似问题,那么您很可能很难找到与这种“预期”行为相关的错误。

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>SAPUI5 single file template | nabisoft</title>
            <script src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
                id="sap-ui-bootstrap"
                data-sap-ui-theme="sap_bluecrystal"
                data-sap-ui-libs="sap.m"
                data-sap-ui-bindingSyntax="complex"
                data-sap-ui-compatVersion="edge"
                data-sap-ui-preload="async"></script>
                <!-- use "sync" or change the code below if you have issues -->
    
            <script>
                sap.ui.getCore().attachInit(function () {
    
                    sap.ui.define([
                        "sap/m/Text",
                        "sap/m/Button",
                        "sap/ui/model/json/JSONModel"
                    ], function (Text, Button, JSONModel) {
                        "use strict";
    
                        var oModel = new JSONModel({
                            hello : "Hello World"
                        });
                        sap.ui.getCore().setModel(oModel, "core");
    
                        // not in DOM
                        var oText1 = new Text({
                            text : "{core>/hello}"
                        });
                        //oText1.placeAt("text1");      // uncomment this to enable the binding
    
                        // add to DOM
                        var oText2 = new Text({
                            text : "{core>/hello}"
                        });
                        oText2.placeAt("text2");
    
                        // action buttons to display text property of text controls
                        new Button({
                            text : "show oText1",
                            press : function(){
                                alert("oText1.getText() = " + oText1.getText());
                            }
                        }).placeAt("btn1");
    
                        new Button({
                            text : "show oText2",
                            press : function(){
                                alert("oText2.getText() = " + oText2.getText());
                            }
                        }).placeAt("btn2");
    
                    });
                });
            </script>
    
        </head>
    
        <body class="sapUiBody">
            <div id="text1"></div>
            <div id="text2"></div>
            <span id="btn1"></span>
            <span id="btn2"></span>
        </body>
    </html>

    【讨论】:

    • 感谢您的详细解释和示例。我不想让我的回复在回复中迷失,所以我也在评论你的帖子。我遇到了这个项目,其中核心绑定工作github.com/qmacro/w3u3_redonebasic/tree/xmlviews。与我的项目不同的是,我使用本指南 openui5beta.hana.ondemand.com/#docs/guide/… 添加了路由。似乎路由会影响这种行为?
    • @quikbeam 您介意发布您的 manifest.json 和 Component.js 文件吗?我还用我的代码证明了它必须有效。如果它不起作用,则说明有问题。使用路由根本不应该是一个问题,除非你的代码做“一些特别的事情”。
    【解决方案4】:

    sap.ui.getCore()this.getView() 返回的对象不是同一个对象,我认为这很明显为什么不起作用。

    您试图从另一个对象(核心)获取一个对象(模型),尽管所需的模型绑定到另一个对象(视图)

    就像我有两个彩色盒子(一个红色,一个蓝色),我试图从蓝色盒子中得到红色

    这是一个类似的问题,但这个问题的原因取决于 UI5 框架中视图的 id 处理: https://scn.sap.com/thread/3551589

    可以看到核心和视图不返回同一个对象

    还可以查看 openui5 网站上的数据绑定部分:https://openui5beta.hana.ondemand.com/#docs/guide/e5310932a71f42daa41f3a6143efca9c.html

    在 components.js 中创建模型:

    var oModel= new sap.ui.model.json.JSONModel;
    oModel.loadData("webapp/controller/app.json");
    this.setModel(oModel, "app");
    

    获取模型: 这将创建对已在 Components.js 中创建的模型的引用

    var oModel= this.getView().getModel("app");
    

    使用“{modelName(app)>desiredProperty}”引用模型

    <Input type="Password" placeholder="{app>Password}"
                        value="{app>mlsUser/password}" />
    

    你能发布你的 json 内容吗?

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 2017-10-22
      • 1970-01-01
      • 2012-02-16
      • 2021-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多