SAPUI5 - 'getService' of undefined - sapui5

I am working on variant management using shell. I got 'getService' of undefined error in FLP. After adding below libraries, It worked.
Index.html
<script>
window["sap-ushell-config"] = {
defaultRenderer : "fiori2",
renderers: {
fiori2: {
componentData: {
config: {
search: "hidden"
}
}
}
},
applications: {
"OrderTracking-display": {
additionalInformation: "SAPUI5.Component=orders",
applicationType: "URL",
url: ".",
title: "Order Tracking"
}
}
};
</script>
<script src="/sap/public/bc/ui5_ui5/resources/sap/ushell_abap/bootstrap/abap.js" id="sap-ushell-bootstrap"></script>
<script id="sap-ui-bootstrap"
src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-libs="sap.ushell, sap.collaboration, sap.m, sap.ui.commons,
sap.ui.layout, sap.ui.ux3"
data-sap-ui-theme="sap_belize"
data-sap-ui-bindingSyntax="complex"
data-sap-ui-compatVersion="edge"
data-sap-ui-resourceroots='{"orders": "."}'
data-sap-ui-frameOptions="trusted">
manifest.json
"sap.ui5": {
"rootView": {
"viewName": "orders.view.App",
"type": "XML",
"async": true,
"id": "app"
},
"dependencies": {
"minUI5Version": "1.42.0",
"libs": {
"sap.ui.core": {},
"sap.m": {},
"sap.f": {},
"sap.ushell": {},
"sap.collaboration": {
"lazy": true
}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "orders.i18n.i18n"
}
},
"": {
"dataSource": "mainService",
"preload": true
}
},
"services": {
"ShellUIService": {
"factoryName": "sap.ushell.ui5service.ShellUIService",
"lazy": false,
"settings": {
"setHierarchy": "auto",
"setTitle": "auto"
}
}
},
But I couldn't find ui5service.ShellUIService under sap.ushell. Also popups & date pickers is not working. How to make both sap.ushell.ui5service &
sap.ushell.services libraries work.
Below are the errors I get
Error -1
Error -2
There is no 'ui5service' under 'ushell'
sap.ushell

The index.html file is used to run an app from the WebIDE in test mode during development. A local launchpad called a Sandbox is created to run the app but not all services from launchpad (cloud or abap) are available.
The libraries that the app needs must be defined in the javascript files where they are needed.

Related

Implement I18n localization in Strapi local plugins

I generated a local plugin and created an article model using:
"pluginOptions": {
"i18n": {
"localized": true
}
},
inside his article.settings.json file, in order to make some specific fields translatables using the Internationalization(I18N) plugin
Problem is, while running the command:
strapi develop --watch-admin
I end up having the following errors:
error Something went wrong in the model "Article" with the attribute "localizations"
error TypeError: Cannot read property "uid" of undefined
Removing the "pluginOptions" instead, gives my local plugin running without any translatable field or articles__translations pivot that should be generated into my mysql database
"pluginOptions" is the very same parameter that gets generated into the model settings creating a collection type using the Content-Types Builder, but I can't have it to work while using it for a local plugin.
Here is my article.settings.json:
plugins/blog/models/article.settings.json
{
"kind": "collectionType",
"collectionName": "articles",
"info": {
"name": "article"
},
"options": {
"draftAndPublish": false,
"timestamps": true,
"populateCreatorFields": true,
"increments": true,
"comment": ""
},
"pluginOptions": {
"i18n": {
"localized": true
}
},
"attributes": {
"title": {
"pluginOptions": {
"i18n": {
"localized": true
}
},
"type": "string",
"required": true,
"maxLength": 255,
"minLength": 3
},
"slug": {
"pluginOptions": {
"i18n": {
"localized": true
}
},
"type": "uid",
"targetField": "title",
"required": true
},
"featured": {
"pluginOptions": {
"i18n": {
"localized": false
}
},
"type": "boolean",
"default": false
},
"published_date": {
"pluginOptions": {
"i18n": {
"localized": false
}
},
"type": "datetime"
},
}
}
You can use the content-type-builder plugin as a workaround. You would not create the content type under the content-types folder but create it programmatically.
As an example of a very simple tag content type:
{
"singularName": "tag",
"pluralName": "tags",
"displayName": "tag",
"description": "",
"draftAndPublish": false,
"pluginOptions": {
"i18n": {
"localized": true
}
},
"attributes": {
"label": {
"type": "string",
"pluginOptions": {
"i18n": {
"localized": true
}
},
"unique": true
}
}
}
Note, this schema of the json is a bit different from the ones in plugin/server/content-types.
Then you can create the content type programmatically like this:
import { Strapi } from "#strapi/strapi";
import tag from "../content-types/tag.json";
import page from "../content-types/page.json";
export default ({ strapi }: { strapi: Strapi }) => ({
async createContentComponent() {
if (!tag) return null;
try {
const components: any = [];
const contentType = await strapi
.plugin("content-type-builder")
.services["content-types"].createContentType({
contentType: tag,
components,
});
return contentType;
} catch (e) {
console.log("error", e);
return null;
}
},
});
This is exactly how the admin creates content types using the content builder UI.
And it works using the pluginOptions.i18n.localized: true.
One approach would be to do this, e.g., on the bootstrap phase of the plugin. Here you could also check whether or not the contents are created or not.
As a bonus, you can also create components that otherwise would not work.
Hope that helps.
Links:
Create components programmatically in a plugin: https://github.com/strapi/strapi-plugin-seo/blob/main/server/services/seo.js
Create content types:
https://github.com/strapi/strapi/blob/88caa92f878a068926255dd482180202f53fcdcc/packages/core/content-type-builder/server/controllers/content-types.js#L48
EDIT:
You could also keep the original schema and use this fn to transform it - at least for now as long as the other approach is not working:
https://github.com/strapi/strapi/blob/1eab2fb08c7a4d3d40a5a7ff3b2f137ce0afcf8a/packages/core/content-type-builder/server/services/content-types.js#L37

When will Component.js be loaded?

I'm trying to run a SAPUI5 application. I created a view with a view piecharts and add them in index.html to the body by referring to its ID content
<script>
var app = new sap.m.App();
var page = sap.ui.view({
viewName: "...",
type: sap.ui.core.mvc.ViewType.XML
});
app.addPage(page);
app.placeAt("content");
</script>
My problem now is that the Component.js isn't called. So I have no chance of using Routing since the Router isn't initialized.
I tried some different ways, like this:
<script>
sap.ui.getCore().attachInit(function() {
new sap.m.Shell({
app: new sap.ui.core.ComponentContainer({
height: "100%",
name: "vizFrame.gettingStarted.demoVizFrame"
})
}).placeAt("content");
});
</script>
After this approach, the Component.js got triggered, but the page is empty. The content of my root view isn't displayed.
manifest.json
{
"_version": "1.12.0",
"sap.app": {
"id": "vizFrame.gettingStarted.demoVizFrame",
"type": "application",
"i18n": "i18n/i18n.properties",
"applicationVersion": {
"version": "1.0.0"
},
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"sourceTemplate": {
"id": "ui5template.basicSAPUI5ApplicationProject",
"version": "1.40.12"
}
},
"sap.ui": {
"technology": "UI5",
"icons": {
"icon": "",
"favIcon": "",
"phone": "",
"phone#2": "",
"tablet": "",
"tablet#2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
}
},
"sap.ui5": {
"flexEnabled": false,
"rootView": {
"viewName": "vizFrame.gettingStarted.demoVizFrame.view.VizChart",
"type": "XML"
},
"dependencies": {
"minUI5Version": "1.60.1",
"libs": {
"sap.ui.layout": {},
"sap.ui.core": {},
"sap.m": {}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "vizFrame.gettingStarted.demoVizFrame.i18n.i18n"
}
}
},
"resources": {
"css": [
{
"uri": "css/style.css"
}
]
},
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"async": true,
"viewPath": "vizFrame.gettingStarted.demoVizFrame.view",
"controlAggregation": "pages",
"controlId": "app",
"clearControlAggregation": false
},
"routes": [
{
"name": "RouteVizChart",
"pattern": "RouteVizChart",
"target": ["TargetVizChart"]
},
{
"pattern": "detail",
"name": "detail",
"target": "detail"
}
],
"targets": {
"TargetVizChart": {
"viewType": "XML",
"transition": "slide",
"clearControlAggregation": false,
"viewId": "VizChart",
"viewName": "VizChart"
},
"testView": {
"viewType": "XML",
"viewName": "testView",
"viewId": "testView",
"viewLevel": 2
},
"detail": {
"viewType": "XML",
"viewName": "detailView"
}
}
}
}
}
Component.js
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/Device",
"vizFrame/gettingStarted/demoVizFrame/model/models"
], function (UIComponent, Device, models) {
"use strict";
return UIComponent.extend("vizFrame.gettingStarted.demoVizFrame.Component", {
metadata: {
manifest: "json"
},
init: function () {
UIComponent.prototype.init.apply(this, arguments);
this.getRouter().initialize();
this.setModel(models.createDeviceModel(), "device");
}
});
});
VizChart.view.xml
This is the root view where only the page title gets displayed:
<mvc:View controllerName="vizFrame.gettingStarted.demoVizFrame.controller.VizChart"
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
xmlns:viz="sap.viz.ui5.controls"
xmlns:chart="sap.suite.ui.commons"
xmlns:l="sap.ui.layout"
>
<Page title="Übersicht">
<l:VerticalLayout
width="100%"
class="gridWrapper">
<l:Grid containerQuery="true">
<viz:VizFrame xmlns="sap.viz" id="l100" width="100%" selectData="onDataClick" />
<viz:VizFrame xmlns="sap.viz" id="l300" width="100%" selectData="onDataClick" />
<viz:VizFrame xmlns="sap.viz" id="l400" width="100%" selectData="onDataClick" />
<viz:VizFrame xmlns="sap.viz" id="l430" width="100%" selectData="onDataClick" />
<viz:VizFrame xmlns="sap.viz" id="l499" width="100%" selectData="onDataClick" />
</l:Grid>
</l:VerticalLayout>
</Page>
</mvc:View>
The topic App Initialization: What Happens When an App Is Started? explains which files are loaded in which order generally. In most cases, a Component is loaded with its descriptor (manifest.json) once the ComponentContainer is instantiated.
About the issue with the page being empty, see my other answer in stackoverflow.com/a/50951902.
In your case, the root view is missing a root control (e.g. sap.m.App). So it should be:
<!-- Root view -->
<mvc:View xmlns:mvc="sap.ui.core.mvc">
<App id="app" xmlns="sap.m">
<!-- Leave this block empty if Router should be used. Otherwise, continue.. -->
<Page title="Übersicht">
<!-- content -->
</Page>
</App>
</mvc:View>
In your 1st snippet, you could see the page content because there was already sap.m.App.
ComponentContainer loads component.js file from index.html
component.js loads component descriptor(manifest.json - application descriptor file to declare dependencies) which is referenced in the file.
component.js create root view, default and resource(i18n) model.
index.html
sap.ui.getCore().attachInit(function () {
new sap.ui.core.ComponentContainer({
name: "ABC.AppName"
}).placeAt("content");
});
component.js
sap.ui.core.UIComponent.extend("ABC.AppName.Component", {
metadata : {
includes: [jQuery.device.is.phone ? "assets/css/mStyle.css" : "assets/css/dStyle.css"]
},
createContent: function () {
// create root view
var oView = sap.ui.view({
id: "app",
viewName: "ABC.AppName.ViewFolder.App",
type: "JS",
viewData: { component: this },
});
i18nGlobal = new sap.ui.model.resource.ResourceModel({
bundleUrl: "i18n/i18n.properties",
bundleLocale: "de"
});
oView.setModel(i18nGlobal, "i18n");
sap.ui.getCore().setModel(i18nGlobal, "i18n");
return oView;
}
});

Two bindings works by calling backend. One binding won't call backend

Can you help me solve this mystery? I got the walkthrough example in step 10 and adapted it so I can create a simple binding to an OData service.
Let me share the main files:
Component.js
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/model/json/JSONModel"
], function(UIComponent, JSONModel) {
"use strict";
return UIComponent.extend("BasicMessages.Component", {
metadata: {
manifest: "json"
},
init: function() {
// call the init function of the parent
UIComponent.prototype.init.apply(this, arguments);
// set data model
var oData = {
recipient: {
name: "World"
}
};
var oModel = new JSONModel(oData);
this.setModel(oModel, "json");
},
});
});
Manifest.json (hid the service URI, but it's properly configured)
{
"_version": "1.8.0",
"sap.app": {
"id": "BasicMessages",
"type": "application",
"i18n": "i18n/i18n.properties",
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"applicationVersion": {
"version": "1.0.0"
},
"dataSources": {
"mainService": {
"uri": "hidden_service_uri",
"type": "OData",
"settings": {
"odataVersion": "2.0",
"localUri": "localService/metadata.xml"
}
}
}
},
"sap.ui": {
"technology": "UI5",
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
}
},
"sap.ui5": {
"rootView": {
"viewName": "BasicMessages.view.App",
"type": "XML",
"async": true,
"id": "app"
},
"dependencies": {
"minUI5Version": "1.30",
"libs": {
"sap.m": {}
}
},
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "BasicMessages.i18n.i18n"
}
},
"": {
"dataSource": "mainService",
"settings": {
"defaultUpdateMethod": "PUT",
"useBatch": false,
"metadataUrlParams": {
"sap-documentation": "heading"
},
"defaultBindingMode": "TwoWay"
}
}
}
}
}
App.controller.js
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/m/MessageToast"
], function(Controller, MessageToast) {
"use strict";
return Controller.extend("BasicMessages.controller.App", {
onInit: function() {
this.getView().setModel(this.getOwnerComponent().getModel());
},
onShowHello: function() {
// read msg from i18n model
var oBundle = this.getView().getModel("i18n").getResourceBundle();
var sRecipient = this.getView().getModel("json").getProperty("/recipient/name");
var sMsg = oBundle.getText("helloMsg", [sRecipient]);
// show message
MessageToast.show(sMsg);
},
});
});
App.view.xml (this is the tricky file)
<mvc:View controllerName="BasicMessages.controller.App"
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m">
<Button text="{i18n>showHelloButtonText}" press="onShowHello" />
<Input value="{json>/recipient/name}"
description="Hello {json>/recipient/name}"
valueLiveUpdate="true" width="60%"
/>
<Text text="{/Caixas(Id='0001',InicioValidade='20180712193002')/Descricao}" />
<List items="{/Caixas}">
<StandardListItem title="{Descricao}" />
</List>
</mvc:View>
If I use the view file exactly like that, it calls the OData service on the backend and retrieve the list and the text element contents.
link to screenshot:
If I comment the list lines, the OData service won't be called and the text element won't be filled with the text.
link to screenshot:
Why does this happen???
Got the answer on SAP Docs
Note: Requests to the back end are triggered by list bindings (ODataListBinding), element bindings (ODataContextBinding), and CRUD functions provided by the ODataModel. Property bindings (ODataPropertyBindings) do not trigger requests.
I think, Rafael explained why this happens (your question), now to answer the unasked question "howto make this work":
You would need to bind the Text control to the entitiy and the text property to the Descricio attribute, basically something like that:
<Text binding="{/Caixas(Id='0001',InicioValidade='20180712193002')" text="{Descricao}" />
(sorry, no ui5 runtime environment at hand, so I didnt actually run this)

Promises do not work (for me)

Probably I'm missing something basic here. Scenario goes like this:
Within the root view controller of my application (App.controller.js, onInit function) I'm performing a series of read operations on a named model in order to have additional data ready mainly for use by formatters in subsequent views. What I have done is using promises to make sure that data will be ready.
Problem is that application occasionally crashes when the initial view with pattern "" (Worklist.view.xml in my case) is loaded after the root view (App.view.xml) because the formatter function can't find the data expected. Added a few break-points and observed the debugger:
stopping at the first read function
stopping at the promises condition at the end
stopping (and throwing error) at the formatter function at the subsequent view
stopping in the success function of oData read (resolve)
page freezes afterwards as result of the exception thrown above
"Normal" flow, when application doesn't crash goes like this:
stopping at the first read function
stopping at the promises condition at the end
stopping in the success function of oData read (resolve)
stopping at the readyToGo function (it's there just for temporary debugging)
stopping at the formatter function at the subsequent view
page display, everything in order
Judging by the above, I have reached the conclusion that my promises do not work. Any ideas?
sap.ui.define([
"kristal/apps/agreements/controller/BaseController",
"sap/ui/model/json/JSONModel"
], function (BaseController, JSONModel) {
"use strict";
/* PROMISE VARIABLES */
var oModelTypeDataDeferred = jQuery.Deferred();
var oModelStatusDataDeferred = jQuery.Deferred();
var oModelRoleDataDeferred = jQuery.Deferred();
var oModelRefDataDeferred = jQuery.Deferred();
var oModelExtOrgDataDeferred = jQuery.Deferred();
var oModelInvolvementDataDeferred = jQuery.Deferred();
return BaseController.extend("kristal.apps.agreements.controller.App", {
onInit: function () {
/* CALLED AFTER PROMISES HAVE BEEN FULFILLED */
var readyToGo = function() {
jQuery.sap.log.error("Ready!");
};
var oViewModel;
var fnSetAppNotBusy;
var iOriginalBusyDelay = this.getView().getBusyIndicatorDelay();
var oViewModel = new JSONModel({
busy: true,
delay: 0
});
this.setModel(oViewModel, "appView");
fnSetAppNotBusy = function() {
oViewModel.setProperty("/busy", false);
oViewModel.setProperty("/delay", iOriginalBusyDelay);
};
this.getOwnerComponent().getModel().metadataLoaded().then(fnSetAppNotBusy);
var oModel = this.getOwnerComponent().getModel("f4");
/* oData READ OPS */
oModel.metadataLoaded().then(function(){
// Initialize additional data
var sPath = "/Agreement_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelTypeDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Agreement_StatusesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelStatusDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Role_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelRoleDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Reference_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelRefDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/External_OrganizationsSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelRefDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Involvement_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelInvolvementDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
/* IF ALL PROMISES FULFILLED, PROCEED */
jQuery.when(oModelTypeDataDeferred, oModelStatusDataDeferred, oModelRoleDataDeferred, oModelRefDataDeferred, oModelExtOrgDataDeferred, oModelInvolvementDataDeferred)
.done().then(jQuery.proxy(readyToGo, this));
},
// ...
});
});
manifest.json:
{
"_version": "1.4.0",
"sap.app": {
"id": "kristal.apps.agreements",
"type": "application",
"i18n": "i18n/i18n.properties",
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"applicationVersion": {
"version": "1.0.0"
},
"dataSources": {
"mainService": {
"uri": "/DEV/sap/opu/odata/SAP/ZCONTRACTS_SRV/",
"type": "OData",
"settings": {
"odataVersion": "2.0",
"localUri": "localService/metadata.xml"
}
}
},
"sourceTemplate": {
"id": "sap.ui.ui5-template-plugin.1worklist",
"version": "1.38.3"
}
},
"sap.ui": {
"technology": "UI5",
"icons": {
"icon": "sap-icon://task",
"favIcon": "",
"phone": "",
"phone#2": "",
"tablet": "",
"tablet#2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"supportedThemes": [
"sap_hcb",
"sap_bluecrystal"
]
},
"sap.ui5": {
"rootView": {
"viewName": "kristal.apps.agreements.view.App",
"type": "XML",
"id": "app",
"async": true
},
"dependencies": {
"minUI5Version": "1.38.0",
"libs": {
"sap.ui.core": {
"minVersion": "1.38.0"
},
"sap.m": {
"minVersion": "1.38.0"
},
"sap.ushell": {
"minVersion": "1.38.0"
},
"sap.collaboration": {
"minVersion": "1.38",
"lazy": true
}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "kristal.apps.agreements.i18n.i18n"
}
},
"": {
"dataSource": "mainService",
"preload": true,
"settings": {
"defaultBindingMode": "TwoWay"
}
},
"f4": {
"dataSource": "mainService",
"preload": true,
"settings": {
"metadataUrlParams": {
"sap-documentation": "heading"
},
"defaultBindingMode": "TwoWay"
}
}
},
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"viewPath": "kristal.apps.agreements.view",
"controlId": "app",
"controlAggregation": "pages",
"bypassed": {
"target": [
"notFound"
]
},
"async": true
},
"routes": [{
"pattern": "",
"name": "worklist",
"target": [
"worklist"
]
}, {
"pattern": "AgreementsSet/{objectId}",
"name": "object",
"target": [
"object"
]
}],
"targets": {
"worklist": {
"viewName": "Worklist",
"viewId": "worklist",
"viewLevel": 1
},
"object": {
"viewName": "Object",
"viewId": "object",
"viewLevel": 2
},
"objectNotFound": {
"viewName": "ObjectNotFound",
"viewId": "objectNotFound"
},
"notFound": {
"viewName": "NotFound",
"viewId": "notFound"
}
}
}
},
"sap.platform.abap": {
"uri": "/sap/bc/ui5_ui5/sap/zctr_contr_mnt/webapp",
"_version": "1.1.0"
}
}
Component.js
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/Device",
"kristal/apps/agreements/model/models",
"kristal/apps/agreements/controller/ErrorHandler"
], function(UIComponent, Device, models, ErrorHandler) {
"use strict";
return UIComponent.extend("kristal.apps.agreements.Component", {
metadata: {
manifest: "json"
},
init: function() {
UIComponent.prototype.init.apply(this, arguments);
this._oErrorHandler = new ErrorHandler(this);
this.setModel(models.createDeviceModel(), "device");
this.setModel(models.createFLPModel(), "FLP");
this.getRouter().initialize();
},
destroy: function() {
this._oErrorHandler.destroy();
// call the base component's destroy function
UIComponent.prototype.destroy.apply(this, arguments);
},
getContentDensityClass: function() {
if (this._sContentDensityClass === undefined) {
// check whether FLP has already set the content density class; do nothing in this case
if (jQuery(document.body).hasClass("sapUiSizeCozy") || jQuery(document.body).hasClass("sapUiSizeCompact")) {
this._sContentDensityClass = "";
} else if (!Device.support.touch) { // apply "compact" mode if touch is not supported
this._sContentDensityClass = "sapUiSizeCompact";
} else {
// "cozy" in case of touch support; default for most sap.m controls, but needed for desktop-first controls like sap.ui.table.Table
this._sContentDensityClass = "sapUiSizeCozy";
}
}
return this._sContentDensityClass;
}
});
});
It was all about moving functionality from the root view to component.js and putting the router initialization into the promise conditions, thank you experts

Remote and local OData service

How can I configure manifest.json file so when I run mockserver(mockserver.html) then it goes to the local json data and when I run index.html (main entry to application) then it goes to the remote service. I have a sample manifest.json file from the documentation but not very clear how remote and local service come into play.
{
"_version": "1.1.0",
"sap.app": {
"_version": "1.1.0",
"id": "xxx",
"type": "application",
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"applicationVersion": {
"version": "1.0.0"
},
"dataSources": {
"mainService": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/",
"type": "OData",
"settings": {
"odataVersion": "2.0",
"localUri": "localService/metadata.xml"
}
}
}
},
"sap.ui": {
"_version": "1.1.0",
"technology": "UI5",
"icons": {
"icon": "",
"favIcon": "",
"phone": "",
"phone#2": "",
"tablet": "",
"tablet#2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"supportedThemes": [
"sap_hcb",
"sap_bluecrystal"
]
},
"sap.ui5": {
"_version": "1.1.0",
"rootView": {
"viewName": "xxx.view.Main",
"type": "XML"
},
"dependencies": {
"minUI5Version": "1.30.0",
"libs": {
"sap.ui.core": {},
"sap.m": {},
"sap.ui.layout": {}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"config": {
"productLocal": "localService/mockdata/products.json",
"productRemote": "/some remote end point"
},
"products": {
"dataSource": "mainService"
}
}
}
Controller code
var oModel = new sap.ui.model.odata.ODataModel("/", true);
//var data = oModel;
//console.log(data);
var inputModel = new JSONModel("../model/inputs.json");
var productsModel = new JSONModel();
oModel.read("/ProductSet",
null,
null,
false,
function _OnSuccess(oData, response) {
console.log(oData);
console.log(response);
var data = {"ProductCollection" : oData.results};
productsModel.setData(data);
},
function _OnError(error) {
console.log(error);
});
//set model(s) to current xml view
this.getView().setModel(inputModel, "inputModel");
this.getView().setModel(productsModel);
Thanks for the help.
You don't need to touch manifest.json file for mocking the service.
In fact, in manifest.json the property of dataSources- localUri: takes relative URL to local metadata document or annotation uri. Not for the service.
I hope your mockserver.html looks like this:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<title>MockServerTutorial</title>
<script id="sap-ui-bootstrap"
src="../../resources/sap-ui-core.js"
data-sap-ui-libs="sap.m"
data-sap-ui-theme="sap_bluecrystal"
data-sap-ui-xx-bindingSyntax="complex"
data-sap-ui-resourceroots='{"sap.ui.demo.MockServer": "../"}'>
</script>
<link rel="stylesheet" type="text/css" href="../css/style.css">
<script>
sap.ui.getCore().attachInit(function() {
sap.ui.require([
"sap/ui/demo/MockServer/localService/mockserver",
"sap/m/Shell",
"sap/ui/core/ComponentContainer"
], function (mockserver, Shell, ComponentContainer) {
mockserver.init();
new Shell({
app: new sap.ui.core.ComponentContainer({
height : "100%",
name : "MockServerTutorial"
})
}).placeAt("content");
});
});
</script>
</head>
<body class="sapUiBody" id="content">
</body>
</html>
You can define your mock server as below:
sap.ui.define([
"sap/ui/core/util/MockServer"
], function(MockServer) {
"use strict";
return {
/**
* Initializes the mock server.
* You can configure the delay with the URL parameter "serverDelay".
* The local mock data in this folder is returned instead of the real data for testing.
* #public
*/
init: function() {
// create
var oMockServer = new MockServer({
rootUri: "/"
});
// simulate against the metadata and mock data
oMockServer.simulate("../localService/metadata.xml", {
sMockdataBaseUrl: "../localService/mockdata",
bGenerateMissingMockData: true
});
// start
oMockServer.start();
jQuery.sap.log.info("Running the app with mock data");
}
};
});
Please make sure you will handle custom urls (with filters/sorts) and
function import properly in mockserver.js.
Read complete steps here