model-view-controller sapui5

model view controller - No se puede acceder al modelo desde el núcleo en sapUI5



model-view-controller (4)

Siga a la pregunta relacionada aquí

Por alguna razón, no puedo acceder a mi modelo en mi vista xml cuando está configurado en sap.ui.getCore (). SetModel (). Si lo configuro en this.getView () no tengo ningún problema.

Mi vista 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>

Mi controlador JS contiene esto para setModel ()

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

De nuevo, si configuro el modelo en this.getView (). SetModel () en lugar de getCore () XML y el controlador funcionan bien juntos. También agregué data-sap-ui-xx-bindingSyntax = "complex" a mi index.html pero eso no pareció marcar la diferencia. Cualquier ayuda sería apreciada.

Editado para incluir más información

Mi Component.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(); } }); });

Mi 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" } ] } } }

Modelo app.json

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

Encontré un ejemplo donde el enlace de núcleo funciona aquí . Es una aplicación mucho más simple. Todavía estoy tratando de descubrir cuáles son las diferencias entre este proyecto y el mío


Me hicieron conocer esta pregunta por una pregunta similar sobre Github

De forma predeterminada, los componentes UI5 no heredan modelos y contextos vinculantes de su entorno (el ComponentContainer donde se ubican). Esto fue hecho por el bien del aislamiento.

Puede cambiar ese comportamiento predeterminado estableciendo la propiedad propagateModel:true para el contenedor:

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

La documentación para propagateModel se puede encontrar en la referencia de la API y en la guía para desarrolladores de UI5 ( el párrafo correspondiente en la última página solo se agregó recientemente, no estaba disponible cuando planteó su pregunta ).

Pero cuando el modelo se crea en el alcance del componente y debe usarse dentro del componente, entonces no debería ser necesario agregarlo al núcleo. Simplemente asignes al componente para compartirlo entre las vistas dentro de ese componente:

Asignarlo desde algún método en un controlador de vista

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

o durante el inicio de 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); }

El enfoque más moderno es configurar el modelo en el archivo manifest.json y dejar que el marco ejemplifique una asignación. Consulte Tutorial Tutorial - Paso 10: Descriptor para Aplicaciones para ver un ejemplo.

Usando cualquiera de estos enfoques, ni siquiera debería haber necesidad de leer y establecer el modelo en otra vista, siempre que esa vista sea un descendiente del componente (parte del árbol de control devuelto por createContent ).


Experimenté el mismo comportamiento. Si creo una aplicación simple de un solo archivo, sin ningún elemento complejo de UI, el enlace basado en el núcleo funciona como un amuleto.

Si creo un contenedor complejo, como una aplicación con un shell, este tipo de enlace ya no funcionará. Parece que estos contenedores ocultan el modelo global de la vista.

Como solución, utilicé el siguiente fragmento de código:

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

O incluso puede vincular el modelo directamente al control donde desea usar.

Ninguno de ellos es la mejor solución si tiene que usar el modelo global en varias vistas / controles, pero eso está funcionando para mí.


En la vista anterior, solo el marcador de posición del campo de contraseña está usando su modelo de aplicación. Si este marcador de posición no se llena correctamente, supongo que el archivo json no se pudo cargar o el contenido no coincide con la ruta de enlace que utiliza en su vista para la propiedad del marcador de posición del campo de contraseña. Para obtener más información, publique también el contenido de su archivo json. Debería verse de alguna manera así:

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

De acuerdo con el enlace en la vista, debe haber una propiedad de "Contraseña" en el nivel raíz del objeto de datos.

A continuación encontrará un ejemplo continuo que debería ayudarlo. Como puede ver, funciona como un amuleto, por lo que puede colocar fácilmente un modelo con nombre en el Núcleo y hacer referencia a él en su vista.

<!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>

En este hilo, algunas personas han mencionado que "sap.ui.getCore () funciona con cosas pequeñas, pero por alguna razón no en aplicaciones más complejas".

@Marc también ha publicado el enlace correcto a los documentos de API , donde puede encontrar lo siguiente:

Un ManagedObject hereda modelos del Core solo cuando es un descendiente de un UIArea

Por supuesto, debes saber qué significa esto para escribir código que haga lo que esperas. Aquí hay un pequeño ejemplo que le dice lo que podría pasar en caso de que tenga un pequeño "malentendido" (ver a continuación).

El código siguiente crea dos instancias de sap.m.Text y vincula sus propiedades de texto a un JSONModel, que está disponible como un modelo llamado "core" directamente en el Core (recuperado con sap.ui.getCore ()). Hay 2 botones, uno para cada instancia de sap.m.Text. En los controladores de prensa correspondientes de los botones, simplemente visualizo la propiedad de texto de la instancia sap.m.Text correspondiente. Como puede ver, ambas instancias sap.m.Text están vinculadas a la misma propiedad en JSONModel. Sin embargo, solo se agrega el segundo texto sap.m. al DOM.

Ahora la parte interesante, que podría estar relacionada con la confusión de este hilo: Solo la propiedad de texto del segundo control sap.m.Text contiene el texto esperado "Hello World" del JSONModel. ¡La propiedad de texto del primer control de sap.m.Text no tiene el valor "Hello World" del modelo! ¡Este es el comportamiento esperado de SAPUI5 y está documentado! Así que supongo que en caso de que tenga problemas similares en su propia aplicación "compleja", entonces es muy probable que tenga un error difícil de encontrar relacionado con este comportamiento "esperado".

<!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>


sap.ui.getCore() y this.getView() no devuelven el mismo objeto, creo que es obvio por qué esto no funciona.

Está intentando obtener un objeto (modelo) de otro objeto (el núcleo) aunque el modelo deseado está vinculado a otro objeto (la vista)

es como si tuviera dos cajas de colores (una roja, una azul) y estoy tratando de obtener el color rojo de la caja de color azul

Aquí hay un problema similar, pero la causa de esto depende del manejo de la id de las vistas en el marco UI5: https://scn.sap.com/thread/3551589

Puede ver el núcleo y la vista no devuelve el mismo objeto .

También revise la sección de enlace de datos en el sitio web de openui5: https://openui5beta.hana.ondemand.com/#docs/guide/e5310932a71f42daa41f3a6143efca9c.html

Crear modelo en components.js:

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

Obtener modelo: esto creará una referencia al modelo que se ha creado en Components.js

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

Consulte el modelo con "{modelName (app)> desiredProperty}"

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

¿podrías publicar tu contenido json?

Espero que esto haya sido útil