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();
}
}
Related
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
I have a nice and simple API swagger standard layout documentation url, auto generated by the rho-routes swagger support. I want to customize the layout with let's say colors, logo, phrases and examples.
In my scala backend the SwaggerUI service is generated by this:
case GET -> Root =>
implicitly[Applicative[F]].pure(
Response[F]()
.withStatus(Status.SeeOther)
.withHeaders(Location(Uri.fromString(
s"${webjarPath}/swagger-ui/3.40.0/index.html?url=${swaggerApiJsonPath}&layout=BaseLayout").right.get)
)
)
}
Is it possible to customize this "BaseLayout" direclty from the backend without importing a React dependency? If not: can I redirect the whole thing on my website to customize it from a ReactJS repo? If yes, how? Do I need a swagger npm integration? I'm a backend dev and I'm not very solid on FE infrastructures matters.
I'd appreciate someone to pointing me some articles or solutions I can study and apply with this case. Thanks all
You serve a webjar which is easy to set up but difficult (if not impossible, I'm no expert) to customize.
What you can do to at least serve a customized Swagger UI, is handle it like any Play Twirl template:
add all the Swagger frontend resources needed in your project:
find the links in the /app/views/index.scala.html contents below. I have:
ls public/swagger-ui
swagger-ui-bundle.js swagger-ui.js
oauth2-redirect.html swagger-ui.css swagger-ui-standalone-preset.js
call the template from your controller:
See https://www.playframework.com/documentation/2.8.x/ScalaTemplates as well
def api: Action[AnyContent] =
Action { implicit request =>
Ok(views.html.index(s"https://${appConfig.apiUrl}", giveItSomeArgs)
}
customize your Swagger in the Twirl template:
mine is in /app/views/index.scala.html:
#import play.api.libs.json.JsValue
#import play.api.libs.json.Json
#(apiUrl: String, giveItSomeArgs: Set[String])
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="assets/swagger-ui/swagger-ui.css" >
<link rel="icon" type="image/png" href="../favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="../favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="assets/swagger-ui/swagger-ui-bundle.js"> </script>
<script src="assets/swagger-ui/swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "/assets/openapi.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl,
{
statePlugins: {
spec: {
wrapActions: {
updateJsonSpec: function(oriAction, system) {
return (spec) => {
// change spec.servers here to add new entry, use concat to put it as the first & default one
spec.servers = [{url: "#apiUrl"}]
spec.components.schemas["swagger"]["docs"]["are"]["very"]["dynamic"] = #Html(Json.toJson(giveItSomeArgs).toString);
return oriAction(spec)
}
}
}
}
}
}
],
layout: "StandaloneLayout",
onComplete: function() {
}
})
// End Swagger UI call region
window.ui = ui
}
</script>
</body>
</html>
There's your layout StandaloneLayout so I guess you have a handle there. You can add all the JavaScript in the world and knock yourself out. Check the Swagger docs on how to customize the layout.
Not sure about the whole React thing you suggest, that's another thing.
I am fairly new to openui5. I want to include summernote editor into my application. I have included the cdn links from their homepage but I am getting the following error
ShellRenderer-dbg.js:143 Uncaught (in promise) TypeError: Cannot read property 'require' of undefined
at Object.S.getLogoImageHtml (ShellRenderer-dbg.js:143)
at Object.S.render (ShellRenderer-dbg.js:86)
at R.renderControl (RenderManager-dbg.js:1004)
at R.render (RenderManager-dbg.js:1259)
at constructor.U.rerender (UIArea-dbg.js:629)
at constructor.Core.renderPendingUIUpdates (Core-dbg.js:2774)
at constructor.Core.init (Core-dbg.js:1235)
at Core-dbg.js:485
at a (Core-dbg.js:179)
at SyncPoint.finishTask (Core-dbg.js:173)
Any ideas would be much appreciated. Thanks
I've managed to get this working in a simple scenario but not sure how it will work with other UI5 elements & re-rendering etc. I've created a simple control to show how it could interact with UI5 but it would need some work!
Notes: SAPUI5 contains jQuery in the default library, although there is a non-jQuery version available so you can use your own version of jQuery, I am not sure of the version needed to get both working optimally overlap. Additionally, Summernote seems to require bootstrap CSS + JS and not sure if that will work with UI5 too, especially if this is to be deployed in a Launchpad scenario. Could be OK as a standalone app though!
Have fun!
sap.ui.define([
"sap/ui/core/Control"
], function (Control) {
"use strict";
return Control.extend("MySummernoteControl", {
metadata: {
properties: {},
aggregations: {},
events: {}
},
renderer: {
apiVersion: 2,
render: function(rm, oButton) {
rm.openStart("div", oButton);
rm.openEnd();
rm.close("div");
}
},
onAfterRendering: function () {
if (!this._rendered) {
this.$().summernote();
this._rendered = true;
}
}
});
});
const ctrl = new MySummernoteControl();
ctrl.placeAt("content");
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
<script
src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-theme="sap_fiori_3"
data-sap-ui-xx-bindingSyntax="complex"
data-sap-ui-libs="sap.m"></script>
<!-- include bootstrap -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<!-- include summernote css/js -->
<link href="https://cdn.jsdelivr.net/npm/summernote#0.8.18/dist/summernote.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/summernote#0.8.18/dist/summernote.js"></script>
</head>
<body class="sapUiBody sapUiSizeCompact">
<div id='content'></div>
</body>
</html>
I created a custom extension for sap.m.Input. In onAfterRendering I want to mask the value using using jquery-maskmoney as follows:
$('#'+this.getId()+'-inner').maskMoney({ thousands : '', decimal : '.' });'
When I apply mask in the console, everything works fine. But when I try to
add it in the onAfterRendering method, I get some errors when I am trying to setValue:
amountInputControl.setValue(data.amount); // Its is an instance of NumericInput
Error:
TypeError: Cannot read property 'val' of undefined
at sap.m.InputBase._getInputValue (InputBase.js:9)
at sap.m.InputBase.updateDomValue (InputBase.js:32)
at sap.m.InputBase.setValue (InputBase.js:34)
at sap.ui.controller.updateFieldsForReference //Here was executed operation setValue
NumericInput.js
jQuery.sap.declare("control.customInputTypes.NumericInput");
sap.ui.define(['jquery.sap.global', 'sap/m/Input'],
function(jQuery, BaseInput) {
"use strict";
var commonControlInput = BaseInput.extend('control.customInputTypes.NumericInput', /** #lends sap.m.Input.prototype */ {
metadata: {},
renderer : {
render : function(oRm, oControl) {
sap.m.InputRenderer.render(oRm, oControl);
}
}
});
commonControlInput.prototype.onAfterRendering = function () {
$('#'+this.getId()+'-inner').maskMoney({ thousands : '', decimal : '.' });
};
return commonControlInput;
}, /* bExport= */ true);
I didn't even touch the InputBase class, so I wonder whats wrong? If I don't apply this mask everything works fine.
Maybe I cannot use jQuery in the onAfterRendering method of a control?
At first I tought you might want to check sap.m.MaskInput, but I guess that's not exactly what you want...
Anyway, there are a few things I would change in your code. Here is a running jsbin example:
<!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 src="https://cdnjs.cloudflare.com/ajax/libs/jquery-maskmoney/3.0.2/jquery.maskMoney.min.js"></script>
<!-- XMLView -->
<script id="myXmlView" type="ui5/xmlview">
<mvc:View
controllerName="MyController"
xmlns="sap.m"
xmlns:core="sap.ui.core"
xmlns:mvc="sap.ui.core.mvc"
xmlns:cit="control.customInputTypes">
<cit:NumericInput value="1219999234" />
</mvc:View>
</script>
<script>
sap.ui.getCore().attachInit(function () {
"use strict";
//### Custom Control ###
// remove the first parameter in "real" apps
sap.ui.define("control/customInputTypes/NumericInput",[
"jquery.sap.global",
"sap/m/Input",
"sap/m/InputRenderer"
], function(jQuery, Input, InputRenderer) {
"use strict";
return Input.extend("control.customInputTypes.NumericInput", {
init : function () {
this.addEventDelegate({
onAfterRendering : function(){
var $input = jQuery("#"+this.getId()+"-inner");
$input.maskMoney({
thousands : ".",
decimal : ","
}).maskMoney("mask");
}.bind(this)
});
},
renderer : InputRenderer
});
});
//### Controller ###
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function (Controller) {
"use strict";
return Controller.extend("MyController", {
onInit : function () {
}
});
});
//### 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>
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".