Walkthrough step "XML Views" - sapui5

I am a beginner in SAPUI5 and I am trying to learn it through SAP demo kit. However, I am having some problem with the step 4.
I did as mentioned in the tutorial but I am always getting an error saying that resource cannot be loaded.
The view is created under webcontent in a folder named VIEW and the name of view is APP.
so Project->webcontent->View->app.xml
Error is
Error: resource view/App.view.xml could not be loaded from ./view/App.view.xml. Check for 'file not found' or parse errors. Reason: Not Found
Here is the code in my view.
<mvc:View
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc">
<Text text="Hello World"/>
</mvc:View>
And in Index file
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='X-UA-Compatible' content='IE=edge' />
<title>Hello World</title>
<script id='sap-ui-bootstrap'
src='resources/sap-ui-core.js'
data-sap-ui-theme='sap_bluecrystal'
data-sap-ui-libs='sap.m'
data-sap-ui-compatVersion='edge'
data-sap-ui-preload='async'>
</script>
<script>
sap.ui.localResources("view.App");
sap.ui.getCore().attachInit(function () {
new sap.ui.xmlview({
viewName: "view.App"
}).placeAt("content");
});
</script>
</head>
<body class='sapUiBody'>
<div id='content'></div>
</body>
</html>
However, if I program in a different way, it works. Please check the code below:
<mvc:View
xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"
controllerName="view.app">
<Text text="Hello World"/>
</mvc:View>
In index file
<script>
sap.ui.localResources("view.app");
var app = new sap.m.App({
initialPage:"idmain1"
});
var page = sap.ui.view({
id: "idmain1",
viewName: "view.app",
type: sap.ui.core.mvc.ViewType.XML
});
app.addPage(page);
app.placeAt("content");
</script>

I think the issue looking at your description is the folder where the views are placed are named as View
so Project->webcontent->View->app.xml
Code is
sap.ui.localResources("view.App");
sap.ui.getCore().attachInit(function () {
new sap.ui.xmlview({
viewName: "view.App"
}).placeAt("content");
});
So 3 issues
Folder name is View ====> code is called as view(case sensitive).
View is called app.xml =====> Code is invoked as App(case
sensitive again)
The views are generally called app.view.xml but
you structure says as app.xml need to check this as well.
By fixing these the app should render.

Please check View path in manifest.json ,When creating XML view function has created like this
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"async": true,
"viewPath": "First.UI5.view",
"controlAggregation": "pages",
"controlId": "idAppControl",
"clearControlAggregation": false
},
For Example View name is FirstView, we want add viewname in viewpath
"viewPath": "First.UI5.view.FirstView".

Related

Image not displaying in SAP UI5 Webpage

I am new to SAP UI5 and I am trying to develop a webpage with images and instructions. I am unable to display an image in my Webapp and need help with it. I looked through the internet and could not find any proper solution yet. Below is my code. Can you please help me understand what I am missing?
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My App</title>
<script
id="sap-ui-bootstrap"
src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-theme="sap_belize"
data-sap-ui-libs="sap.m"
data-sap-ui-compatVersion="edge"
data-sap-ui-async="true"
data-sap-ui-onInit="module:sap/ui/demo/walkthrough/index"
data-sap-ui-resourceroots='{
"sap.ui.demo.walkthrough": "./"
}'>
</script>
<style>
.myimage{float:right !important; width:300px; height:200px;}
</style>
</head>
<body class="sapUiBody" id="content">
</body>
</html>
App.view.xml:
<mvc:View
controllerName="sap.ui.demo.walkthrough.controller.App"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc"
>
<Page title="Image">
<content>
<Image id="QRCode" src="images/img1.jpg" />
</content>
</Page>
</mvc:View>
App.controller.js:
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function(
Controller
) {
"use strict";
return Controller.extend("sap.ui.demo.walkthrough.controller.App", {
onBeforeRendering: function() {
this.getView().byId("QRCode").addStyleClass("myimage");
},
});
});
index.js:
sap.ui.define([
"sap/ui/core/mvc/XMLView"
], function (XMLView) {
"use strict";
XMLView.create({
viewName: "sap.ui.demo.walkthrough.view.App"
}).then(function (oView) {
oView.placeAt("content");
});
});
Loading images is a little tricky, especially if you want it to run in the launchpad.
You should create the path dynamically in your controller and put it into a view model:
const sPath = sap.ui.require.toUrl("sap/ui/demo/walkthrough/images/img1.png");
const oModel = new JSONModel({ imagePath: sPath });
this.getView().setModel(oModel, "view");
<Image id="QRCode" src="{view>/imagePath}" />
Of course it's very important to pass the correct namespace to sap.ui.require.toUrl

How to disable letterboxing and adjust UI5 for the widescreen?

I have an UI5-based app (1.66+), which works correctly, but there are huge empty spaces on the left and right sides of the screen (aka letterboxing is on):
I want to disable letterboxing to use the entire screen space.
I tried the following approaches so far:
To use "fullWidth": true in sap.ui section of manifest.json
To add desktop-related classes to the HTML-tag in index.html:
<html class="sap-desktop sapUiMedia-Std-Desktop sapUiMedia-StdExt-LargeDesktop">
To add appWidthLimited: false to index.html:
<script>
sap.ui.getCore().attachInit(function () {
new sap.m.Shell({
app: new sap.ui.core.ComponentContainer({
height: "100%",
name: "APPNAME"
}),
appWidthLimited: false
}).placeAt("content");
});
</script>
Just like it is described in «How to customise Shell container in SAPUI5».
But none of them works for me.
Update:
I succeeded to solve the issue via a static XML-template — just add <Shell id="shell" appWidthLimited="false"> to the main XML-template, but now I want to understand how to implement it via JS in new sap.m.Shell(…) definition.
The starting point for code experiments is below.
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>widescreen</title>
<script id="sap-ui-bootstrap"
src="../../resources/sap-ui-core.js"
data-sap-ui-theme="sap_fiori_3"
data-sap-ui-resourceroots='{"letterboxing.widescreen": "./"}'
data-sap-ui-compatVersion="edge"
data-sap-ui-oninit="module:sap/ui/core/ComponentSupport"
data-sap-ui-async="true"
data-sap-ui-frameOptions="trusted">
</script>
</head>
<body class="sapUiBody">
<div data-sap-ui-component data-name="letterboxing.widescreen" data-id="container" data-settings='{"id" : "widescreen"}' id="content"></div>
</body>
</html>
Component.js:
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/Device",
"letterboxing/widescreen/model/models"
], function (UIComponent, Device, models) {
"use strict";
return UIComponent.extend("letterboxing.widescreen.Component", {
metadata: {
manifest: "json"
},
init: function () {
// call the base component's init function
UIComponent.prototype.init.apply(this, arguments);
// enable routing
this.getRouter().initialize();
// set the device model
this.setModel(models.createDeviceModel(), "device");
}
});
});
Ok, so there seems to be many similar questions regarding how to disable/enable letterboxing. This answer should provide a solution for each case:
Standalone Apps
Look for the instantiation of sap.m.Shell in your project and configure appWidthLimited accordingly.
For example:
In index.html or index.js
sap.ui.require([
"sap/m/Shell",
"sap/ui/core/ComponentContainer",
], (Shell, ComponentContainer) => new Shell({
appWidthLimited: false|true, // <--
// ...
}).placeAt("content"));
In root view
<Shell xmlns="sap.m" appWidthLimited="false|true">
<App>
<!-- ... -->
Of course, the Shell can be configured dynamically in JS too with myShell.setAppWidthLimited.
Note: if the letterboxing is never required, please reconsider whether <Shell> in your app is necessary at all. There is no purpose of sap.m.Shell if the app is displayed always in full width.
API reference: sap.m.Shell
UX guideline: Letterboxing
Apps on SAP Fiori launchpad (FLP)
The component / app …:
should not contain sap.m.Shell anywhere (please check the root view).
launches from FLP instead (no index.html).
Statically in manifest.json
"sap.ui": {
"fullWidth": true|false,
...
},
Dynamically in runtime
// AppConfiguration required from "sap/ushell/services/AppConfiguration"
AppConfiguration.setApplicationFullWidth(true|false);
API reference: sap.ushell.services.AppConfiguration
UX guideline: Letterboxing
⚠️ Note: letterboxing is currently not supported by apps generated by SAP Fiori elements.
According to Available OpenUI5 Versions the newest OpenUI5 version is 1.65.0. How is you app based on 1.66.0?
Setting appWidthLimited: false on the sap.m.Shell should do the work. Check out this example (plunker / github) (in the Plunker run preview in a new window)
You can achieve that removing the shell control from index.html:
sap.ui.getCore().attachInit(function () {
sap.ui.require(["sap/ui/core/ComponentContainer"], function (ComponentContainer) {
new ComponentContainer({
name: "yourProject",
async: true,
manifest: true,
height: "100%"
}).placeAt("content");
});
});
instead of this:
<script>
sap.ui.getCore().attachInit(function () {
new sap.m.Shell({
app: new sap.ui.core.ComponentContainer({
height: "100%",
name: "APPNAME"
}),
appWidthLimited: false
})
.placeAt("content");
});
</script>
Static implementation via XML-template:
<mvc:View controllerName="letterboxing.widescreen.controller.index" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m">
<Shell id="shell" appWidthLimited="false">
<App id="app">
<pages>
<Page id="page" title="{i18n>title}">
<content></content>
</Page>
</pages>
</App>
</Shell>
</mvc:View>
For dynamic implementation via JS-controller with appWidthLimited: false in sap.m.Shell, see: https://stackoverflow.com/a/55867413
For some reason, AppConfiguration.setApplicationFullWidth(true); does not work for me. I don't have a valid application container.
I solved the problem in this, admittedly hacky, way: In my app controller, I added this implementation of the onAfterRendering method:
onAfterRendering: function () {
var oElement = this.getView().byId("idAppControl").$();
while (oElement && oElement.hasClass) {
if (oElement.hasClass("sapUShellApplicationContainerLimitedWidth")) {
oElement.removeClass("sapUShellApplicationContainerLimitedWidth");
break;
}
oElement = oElement.parent();
}
}

Not able to bind data in master page

i'm not getting any results when i try to display json data in the master page.It just displays no data whereas when i do the same thing in the main view i'm able to display the data.
Here is my code :
Mview.view.xml
<core:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" displayBlock="true"
controllerName="com.firstproject.FirstProject.controller.Mview" xmlns:html="http://www.w3.org/1999/xhtml">
<Page title="Master Page">
<content>
<List id="UserList" items="{users>/Users}" headerText="Users">
<items>
<ObjectListItem title="{users>name}"/>
</items>
</List>
</content>
</Page>
index.html
<!DOCTYPE HTML>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta charset="UTF-8">
<title>FirstProject</title>
<script id="sap-ui-bootstrap"
src="../../resources/sap-ui-core.js"
data-sap-ui-preload="sync"
data-sap-ui-libs="sap.m"
data-sap-ui-theme="sap_belize"
data-sap-ui-compatVersion="edge"
data-sap-ui-resourceroots='{"com.firstproject.FirstProject": "./"}'>
</script>
<link rel="stylesheet" type="text/css" href="css/style.css">
<script>
var app = new sap.m.SplitApp({initialPage:"idMasterPage1"});
var mpage = sap.ui.view({id:"idMasterPage1", viewName:"com.firstproject.FirstProject.view.Mview",type:sap.ui.core.mvc.ViewType.XML});
var dpage = sap.ui.view({id:"idDetailPage1", viewName:"com.firstproject.FirstProject.view.Dview",type:sap.ui.core.mvc.ViewType.XML});
app.addMasterPage(mpage);
app.addDetailPage(dpage);
app.placeAt("content")
</script>
</head>
<body class="sapUiBody" id="content">
</body>
manifest.json
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "com.firstproject.FirstProject.i18n.i18n"
}
},
"users":{
"type":"sap.ui.model.json.JSONModel",
"uri":"model/listdata.json"
}
}
Why is this happening?
Also i'm getting this error with or without any list in the master view
Assertion failed: ManagedObject.apply: encountered unknown setting 'initialPage' for class 'sap.m.SplitApp' (value:'idMasterPage1')
The attribute initialPage is no longer usable as an attribute for the sap.m.SplitApp control. Instead you can use initialMaster association to avoid this message.
var app = new sap.m.SplitApp({initialMaster :"idMasterPage1"});
The entire manifest.json is not evaluated because it's not being loaded at all. Start from OpenUI5 walkthrough and review your code by comparing it with specifically the steps "Component Configuration" and "Descriptor for Applications".

How to add control to items statically

Sometimes in an aggregation binding, I need to add some controls to the generated list of items statically. Is there some elegant solution for this?
Let's say I have a Select with the following code:
<Select width="100%"
items="{project>/Milestones}"
selectedKey="0"
>
<core:Item
key="{project>Id}"
text="{project>Name}"
/>
</Select>
Bound to a model with these data:
{
Milestones: [
{
"Id": 1,
"Name": "Cost Estimation 1",
"Description": "Initial cost estimation"
},
{
"Id": 2,
"Name": "Pid Packages",
"Description": "Ready for RFQs"
},
...
]
}
I want to add an item to the Select with key="0" and value="< Blank >" and have that stay there even when the content of project>/Milestones is changed, but I don't want to add it to the actual aggregation.
The solutions that I have at the moment seem really hackish and create problems later on: creating a new model (property) leads to having the data duplicated in multiple lists and therefor it will probably get out of sync at some point. I've also tried adding the static items through binding events, but this is somewhat error prone and very verbose.
Ok here the promised snippet. First of all, if you just want to add a "blank" item, I recommend you to use ComboBox instead of Select, because you can always delete your selection. I added it to the snippet as well.
But if you want to add an item, you just need to use the addItem() function described here
I also added a button to modify your model, so you can see how the '< Blank >' item remains there even when you change it.
Snippet
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta charset="utf-8">
<title>MVC with XmlView</title>
<!-- Load UI5, select "blue crystal" theme and the "sap.m" control library -->
<script id='sap-ui-bootstrap' src='https://sapui5.hana.ondemand.com/resources/sap-ui-core.js' data-sap-ui-theme='sap_belize_plus' data-sap-ui-libs='sap.m' data-sap-ui-xx-bindingSyntax='complex'></script>
<!-- DEFINE RE-USE COMPONENTS - NORMALLY DONE IN SEPARATE FILES -->
<script id="view1" type="sapui5/xmlview">
<mvc:View xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" controllerName="my.own.controller">
<Title text="With Select" class="sapUiMediumMarginTop"></Title>
<Select id="mySelect" width="100%" items="{ path: 'project>/Milestones', events:{ change: '.onSelectBindingChange' }, templateShareable: false}" selectedKey="0">
<core:Item key="{project>Id}" text="{project>Name}" />
</Select>
<Title text="With ComboBox" class="sapUiMediumMarginTop"></Title>
<ComboBox width="100%" items="{ path: 'project>/Milestones', templateShareable: false}" selectedKey="0">
<core:Item key="{project>Id}" text="{project>Name}" />
</ComboBox>
<Button text="Modify Model" press="onButtonPressed" class="sapUiLargeMarginTop sapUiLargeMarginBottom"></Button>
</mvc:View>
</script>
<script>
// define a new (simple) Controller type
sap.ui.controller("my.own.controller", {
onSelectBindingChange: function(oEvent) {
var oNewItem = new sap.ui.core.Item({
key: 0,
text: "< Blank >"
});
this.getView().byId("mySelect").addItem(oNewItem);
},
onButtonPressed: function(oEvent) {
var aMilestones = this.getView().getModel("project").getProperty("/Milestones");
aMilestones.push({
Id: 4,
Name: "New Milestone",
Description: "Just a model modification"
});
this.getView().getModel("project").setProperty("/Milestones", aMilestones);
}
});
/*** THIS IS THE "APPLICATION" CODE ***/
// create some dummy JSON data
var data = {
Milestones: [{
"Id": 1,
"Name": "Cost Estimation 1",
"Description": "Initial cost estimation",
},
{
"Id": 2,
"Name": "Pid Packages",
"Description": "Ready for RFQs",
},
{
"Id": 3,
"Name": "Certificate Check",
"Description": null,
}
]
};
var oJSONModel = new sap.ui.model.json.JSONModel();
oJSONModel.setData(data);
// instantiate the View
var myView = sap.ui.xmlview({
viewContent: jQuery('#view1').html()
}); // accessing the HTML inside the script tag above
myView.setModel(oJSONModel, "project");
// put the View onto the screen
myView.placeAt('content');
</script>
</head>
<body id='content' class='sapUiBody'>
</body>
</html>

Dynamic link in MessagePopover fragment not showing

I've been developing a UI5 app that uses a model to store notifications. I want to display these notifications inside a MessagePopover that can be triggered using the footer.
The data binding works perfectly. I can see that all the properties are set and match the data inside the model. But the link in the details page is not showing up.
When I use a static Link (i.e. a static link to google.com) that is not using data binding, the link is rendered.
Does anyone of you came across the same problem and has a solution for it?
Here is my code:
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function(BaseController) {
return BaseController.extend("test.Test", {
onShowNotificationPopover: function(oEvent){
if (!this._notificationPopover) {
var oMessageTemplate = new sap.m.MessageItem({
type : '{data>type}',
title : '{data>title}',
subtitle : "{data>subtitle}",
description : '{data>description}',
markupDescription : "{data>markupDescription}",
groupName : "{data>groupName}"
});
var oLink = new sap.m.Link({
text : "{data>link/text}",
href : "{data>link/url}",
target : "_blank"
});
/* Working with static */
// oLink = new sap.m.Link({text: "Google", href: "http://google.com", target: "_blank"})
oMessageTemplate.setLink(oLink);
var oPopover = new sap.m.MessagePopover();
oPopover.bindAggregation("items",{
template: oMessageTemplate,
path: "data>/notifications"
});
this._notificationPopover = oPopover;
this.getView().addDependent(this._notificationPopover);
}
this._notificationPopover.toggle(oEvent.getSource());
}
});
});
The view contains the following:
<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns:f="sap.f" xmlns="sap.m" controllerName="test.Test">
<f:DynamicPage showFooter="true">
<f:footer>
<OverflowToolbar>
<Button icon="sap-icon://message-popup" type="Emphasized"
press="onShowNotificationPopover" />
</OverflowToolbar>
</f:footer>
</f:DynamicPage>
</mvc:View>
And the index.html
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'/>
<script src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-libs="sap.m, sap.f"
data-sap-ui-theme="sap_belize"
data-sap-ui-bindingSyntax="complex"
data-sap-ui-resourceroots='{
"test": "."
}'
>
</script>
<script>
sap.ui.getCore().attachInit(function() {
var oModel = new sap.ui.model.json.JSONModel();
oModel.setData({
notifications: [{
type: "Error",
title: "Title1",
subtitle: "Subtitle",
description: "This is a description and below you should see a link",
markupDescription: false,
groupName: "notification",
link: {
text: "Click here",
url: "http://www.google.com"
}
}]
});
var oView = sap.ui.xmlview("test.Test");
oView.setModel(oModel, "data");
oView.placeAt("content");
});
</script>
</head>
<body class="sapUiBody" role="application">
<div id="content"></div>
</body>
</html>
Example: Popover with dynamic link
Example: Popover with static link
I found a solution for my problem: the event itemPress of MessagePopover.
The event handler inside the controller:
onNotificationItemSelect: function(oEvent){
var oItem = oEvent.getParameter("item"), oBindingContext = oItem.getBindingContext("data");
var oData = oBindingContext.getModel().getProperty(oBindingContext.getPath());
oItem.getLink().setText(oData.link.text);
oItem.getLink().setHref(oData.link.url);
}
And you have to register it:
var oPopover = new sap.m.MessagePopover({
itemSelect: this.onNotificationItemSelect
});
Additional Information
When you display the content of the popover using
console.log(oPopover.getItems()[0].getLink())
the correct properties are shown. see here
But when you search the DOM you can see that the link is copied and does not contain the required binding. see here