How to resolve the error: "The target [...] no viewName defined"? - sapui5

I'm pretty new in SAPUI5 and started to learn the subject on Routing and navigation as you can see in their documentation:
https://ui5.sap.com/#/topic/e5200ee755f344c8aef8efcbab3308fb
Now I did all the changes like they do in their documentation but I have an error that I don't understand why it is being thrown:
The target overview no viewName defined. - EventProvider sap.m.routing.Target
Here is the manifest:
{
"...": "...",
"sap.ui5": {
"_version": "1.1.0",
"resources": {
"css": [
{
"uri": "css/style.css"
}
]
},
"dependencies": {
"minUI5Version": "1.60",
"libs": {
"sap.m": {}
}
},
"...": "...",
"rootView": {
"viewName": "sap.ui.startApp.view.App",
"type": "XML",
"async": true,
"id": "app"
},
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"type": "View",
"viewType": "XML",
"path": "sap.ui.startApp.view",
"controlId": "app",
"controlAggregation": "pages"
},
"routes": [
{
"pattern": "",
"name": "overview",
"target": "overview"
},
{
"pattern": "detail",
"name": "detail",
"target": "detail"
}
],
"targets": {
"overview": {
"id": "overview",
"name": "Overview"
},
"detail": {
"id": "detail",
"name": "Detail"
}
}
}
}
}

Solution
Either add "async": true to /sap.ui5/routing/config/ in manifest.json
Or preferably add "sap.ui.core.IAsyncContentCreation" to the application's UIComponent:
sap.ui.define([
"sap/ui/core/UIComponent",
// ...
], function(UIComponent/*,...*/) {
"use strict";
return UIComponent.extend("my.Component", {
metadata: {
interfaces: [
"sap.ui.core.IAsyncContentCreation", // Available since 1.89.0
],
manifest: "json",
},
// ...
});
});
Analysis
The /sap.ui5/routing/targets properties viewName, viewId, viewPath, and viewLevel are regarded as legacy syntax since UI5 1.58.0 (as part of the initiative to support routing with nested components) and thus it is correct to declare name, id, path, and level respectively instead of viewName, etc.. *
The error "[...] no viewName defined" actually comes from sap/ui/core/routing/sync/Target.js. The /sync part indicates that the views are created synchronously which should be avoided because it's blocking the UI thread of the browser during the routing process. Instead, targets should be created asynchronously which, however, requires an additional flag as shown above.
If the targets are created asynchronously, the error will be gone.
* In case existing apps still need to migrate to the new name, id, path, and level syntax:
Add:
"type": "View" to /sap.ui5/routing/config/ (Cf. commit: ef476f1)
"minUI5Version": "1.98.0" or higher to /sap.ui5/dependencies/ (Cf. commit: 867496d)
The property /sap.ui5/rootView/viewName is not affected.
Related discussion: https://github.com/SAP/openui5/issues/3417

Related

Why it does not show two columns?

I am trying to use Flexible Column Layout on my app and I have trouble with the routing. However it does not show the expected result on the screen.
The routing is defined as follows:
"routing": {
"config": {
"routerClass": "sap.f.routing.Router",
"viewType": "XML",
"async": true,
"viewPath": "com.example.RequestAccess.view",
"controlId": "fcl",
"transition": "slide",
"bypassed": {}
},
"routes": [{
"pattern": "jobprofile",
"name": "jobprofile",
"target": [
"JobProfileSelector",
"JobProfileOrder"
]
}, {
"pattern": ":layout:",
"name": "authorize",
"target": [
"Authorization"
]
}],
"targets": {
"Authorization": {
"viewName": "Authorization",
"controlAggregation": "beginColumnPages"
},
"JobProfileOrder": {
"viewName": "JobProfileOrder",
"controlAggregation": "midColumnPages"
},
"JobProfileSelector": {
"viewName": "JobProfileSelector",
"controlAggregation": "beginColumnPages"
}
}
}
},
when I do the call
var oRouter = this._getRouter();
oRouter.navTo("jobprofile");
it shows one column layout instead two columns. I expect to be two columns, because I have defined:
"pattern": "jobprofile",
"name": "jobprofile",
"target": [
"JobProfileSelector",
"JobProfileOrder"
]
Two targets for the path /jobprofile.
I expect, that the app should show like this:
What am I doing wrong?
Update
I have created an example app https://github.com/softshipper/fclpoc.
Click on Go to jobprofile
and you will redirect to page /jobprofile path. Here I expect, that it is going to show me Second and Third view next to each other, like master detail view.
You have to adjust property layout of your FlexibleColumnLayout in order to have 1, 2 or 3 columns. Default is 1.
In your root view, you already have a binding on this property, which is a good idea.
<FlexibleColumnLayout id="fcl"
stateChange="onStateChanged"
layout="{/layout}"
backgroundDesign="Solid">
</FlexibleColumnLayout>
However, you are not calling function _updateLayout from the App.controller.js anywhere.
I suggest refactoring this controller to adjust the layout based on the active route.

How to reuse a component from another application in UI5 1.38?

Environement
Framework : SAPUI5 V1.38.39
IDE : SAP WEB IDE
Problem
I want to use a SAPUI5 application in another one, in order to do so I found the following resource: https://blogs.sap.com/2017/04/05/sapui5-how-to-reuse-parts-of-a-sapui5-application-in-othermultiple-sapui5-applications/
Code from the app where I want to reuse another one
in component.js in init I used :
var sPath = sHostUrl.includes("webidetesting") ? "https://gtyext.net" : sHostUrl;
jQuery.sap.registerModulePath("ztntapp", `${sPath}/sap/bc/ui5_ui5/sap/ztntapp/`);
And in my view :
<core:ComponentContainer
name="ztntapp"
manifestFirst="true"
component="ztntapp">
</core:ComponentContainer>
and in neo-app.json
{
"path": "/sap/bc/ui5_ui5/sap/ztntapp/",
"target": {
"type": "destination",
"name": "gtyext_net",
"entryPath": "/sap/bc/ui5_ui5/sap/ztntapp/"
},
"description": "namespace.tntapp Resources"
}
Code from the reused app
in component.js
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/Device",
"./model/models"
], function (UIComponent, Device, models) {
"use strict";
return UIComponent.extend("TrackAndTrace.ztntapp.Component", {
metadata: {
manifest: "json"
},
init: function () {
[...]
},
[...]
});
});
in neo-app.json (it is the default one created via SAP WebIDE):
{
"welcomeFile": "/webapp/index.html",
"routes": [
{
"path": "/resources",
"target": {
"type": "service",
"name": "sapui5",
"entryPath": "/resources",
"version": "1.38.45"
},
"description": "SAPUI5 Resources"
},
{
"path": "/test-resources",
"target": {
"type": "service",
"name": "sapui5",
"entryPath": "/test-resources",
"version": "1.38.45"
},
"description": "SAPUI5 Resources"
},
{
"path": "/webapp/resources",
"target": {
"type": "service",
"name": "sapui5",
"entryPath": "/resources",
"version": "1.38.45"
},
"description": "SAPUI5 Resources"
},
{
"path": "/webapp/test-resources",
"target": {
"type": "service",
"name": "sapui5",
"entryPath": "/test-resources",
"version": "1.38.45"
},
"description": "SAPUI5 Test Resources"
}
],
"sendWelcomeFileRedirect": true
}
Error message
Uncaught Error: failed to load 'ztntapp/Component.js' from
https://webidetesting278-a392f.dispatcher.hana.ondemand.com/sap/bc/ui5_ui5/sap/ztntapp/Component.js:
Error: failed to load 'TrackAndTrace/ztntapp/model/models.js' from
resources/TrackAndTrace/ztntapp/model/models.js
Points with neo-app.json :
the application "ztntapp" itself works outside this application
the path for component.js is https://webidetesting278-a392f.dispatcher.hana.ondemand.com/sap/bc/ui5_ui5/sap/ztntapp/Component.js however the path for model somehow become https://webidetesting278-a392f.dispatcher.hana.ondemand.com/webapp/resources/TrackAndTrace/ztntapp/model/models.js (I am not sure why "webapp/resources")
https://webidetesting278-a392f.dispatcher.hana.ondemand.com/sap/bc/ui5_ui5/sap/ztntapp/model/models.js is found, resource should probably be loaded from here instead of /webapp/resources/TrackAndTrace/ but I don't know how to do so
Other research
With the neo-app.json file, the problem is to locate the resource
from the "ztntapp", I seen that there is also a
jQuery.sap.registerResourcePath but I am not sure how to use it for
this case
In your first application (main app) please use manifest.json to add the component usage instead of jQuery.sap.registerModulePath in Component.js:
"componentUsages": {
"ztntapp": {
"name": " TrackAndTrace.ztntapp",
"settings": {},
"componentData": {},
"lazy": true
}
}
Then you need to adjust your main app neo-app.json to enable Run configuration to reach your second app (reuse app)
"routes": [
{
"path": "/webapp/resources/TrackAndTrace/ztntapp",
"target": {
"type": "application",
"name": "ztntapp"
}
},
{
"path": "/resources/TrackAndTrace/ztntapp",
"target": {
"type": "application",
"name": "ztntapp"
}
},
Then for the resue app: Deploy your app, so it becomes registered within the SAP WebIDE Fullstack workspace.
Then for your main app in WebIDE, chose Run > Run Configurations > Add configuration > Run as Web Application > Advanced Settings mark Use my workspace first and then press Get Resource Versions. On the list below, you should see your reuse app listed under Resources Name:
Try with this :
jQuery.sap.registerModulePath("ztntapp", "/sap/bc/ui5_ui5/sap/ztntapp")
instead of
jQuery.sap.registerModulePath("ztntapp", ${sPath}/sap/bc/ui5_ui5/sap/ztntapp/)
Also check this link :
https://answers.sap.com/questions/668485/ui5-failed-to-load-componentjs-while-using-compone.html

How not to display DetailNoObjectsAvailable view via mobile?

I've created a sapui5 project from master-detail template. What I want to achieve is showing an empty list (which is in the master view) via mobile without navigating to DetailNoObjectsAvailable view. I just can't find where DetailNoObjectsAvailable view is called from.
The reason why I want to achieve this is that when there are no objects in the list in the beginning and then an object is added to odata source, I see nothing but 'No objects available' and I can not navigate to the master list to refresh it manually. I have to refresh the whole page in fiori client browser to see it. When the list is not empty in the beginning and I add an object to odata source, the list refreshes automatically and I face no problems seeing it.
I haven't changed anything in the routing definition:
"routes": [
{
"pattern": "",
"name": "master",
"target": [
"object",
"master"
]
}, {
"pattern": "visitors_view/{objectId}",
"name": "object",
"target": [
"master",
"object"
]
}
],
"targets": {
"master": {
"viewName": "Master",
"viewLevel": 1,
"viewId": "master",
"controlAggregation": "masterPages"
},
"object": {
"viewName": "Detail",
"viewId": "detail",
"viewLevel": 2
},
"detailObjectNotFound": {
"viewName": "DetailObjectNotFound",
"viewId": "detailObjectNotFound"
},
"detailNoObjectsAvailable": {
"viewName": "DetailNoObjectsAvailable",
"viewId": "detailNoObjectsAvailable"
},
"notFound": {
"viewName": "NotFound",
"viewId": "notFound"
}
}
The mechanism routing to the notFoundobject is found in manifest.json:
manifest.json: bypassed + target in routing config
"routing": {
"config": {
"routerClass": "sap.f.routing.Router",
"viewType": "XML",
"viewPath": "test.test.view",
"controlId": "layout",
"controlAggregation": "beginColumnPages",
"bypassed": {
-------> "target": "notFound" <--------
},
"async": true
},
"targets": {
"notFound": {
"viewName": "NotFound",
"viewId": "notFound"
}
}
View in webapp/view:
<mvc:View
controllerName="test.test.controller.NotFound"
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m">
<MessagePage
id="page"
title="{i18n>notFoundTitle}"
text="{i18n>notFoundText}"
icon="sap-icon://document">
</MessagePage>
</mvc:View>
That is what you are looking for right?
Maybe your problem is solved by changing from "target": "notFound" to "target": "master" within the bypassed section in manifest.json.
UPDATE: Detail.controller.js
_onBindingChange : function () {
var oView = this.getView(),
oElementBinding = oView.getElementBinding();
// No data for the binding
if (!oElementBinding.getBoundContext()) {
this.getRouter().getTargets().display("detailObjectNotFound"); <------------
// if object could not be found, the selection in the master list
// does not make sense anymore.
this.getOwnerComponent().oListSelector.clearMasterListSelection();
return;
}
Solved the problem by commenting some lines in ListSelector.js. They caused an error in the console, which in its turn was the cause of my problem:
constructor : function () {
this._oWhenListHasBeenSet = new Promise(function (fnResolveListHasBeenSet) {
this._fnResolveListHasBeenSet = fnResolveListHasBeenSet;
}.bind(this));
this.oWhenListLoadingIsDone = new Promise(function (fnResolve, fnReject) {
this._oWhenListHasBeenSet
.then(function (oList) {
oList.getBinding("items").attachEventOnce("dataReceived",
function (oData) {
if (!oData.getParameter("data")) {
fnReject({
list : oList,
error : true
});
}
var oFirstListItem = this.getFirstListItem();
if (oFirstListItem) {
fnResolve({
list : oList,
firstListitem : oFirstListItem
});
}
// else {
// fnReject({
// list : oList,
// error : false
// });
//}
}.bind(this)
);
}.bind(this));
}.bind(this));
},

Routing with Parameters - patternMatched Event Not Fired

I am working on UI5 application using Web IDE and I have created a view where I need to bind the data based on parameter received from last view. But the patternMatched event is not firing.
manifest.json
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"viewPath": "oomsdisplay.pso.com.view",
"controlId": "app",
"controlAggregation": "pages",
"bypassed": {
"target": ["notFound"]
},
"async": true
},
"routes": [{
"pattern": "",
"name": "worklist",
"target": ["worklist"]
}, {
"pattern": "ZISOHSet/{objectId}",
"name": "object",
"target": ["object"]
}, {
"pattern": "ZISOHSet/{objectId}",
"name": "payobject",
"target": ["payobject"]
}],
"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"
},
"payobject": {
"viewName": "PayObject",
"viewId": "payobject",
"viewLevel": 2
}
}
}
Component.js
init: function() {
UIComponent.prototype.init.apply(this, arguments);
// ...
this.getRouter().initialize(); // create the views based on the url/hash
},
Now, I have created a view. When I press the button on view, my second view i.e. PayObject will be called. Here is my code on button press of view one:
fViewPayment: function(oEvent) {
this.getRouter().getTargets().display("payobject", {
objectId: "MyParameterhere"
});
},
Now, here is my PayObejct view's init handler with object matched handler. But it is not working.
onInit: function() {
// ...
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.getRoute("payobject").attachPatternMatched(this._onObjectMatched, this);
},
_onObjectMatched: function(oEvent) { // this event handler is not firing
var sObjectId = oEvent.getParameter("arguments").objectId;
sap.m.MessageBox.show(sObjectId);
// ...
},
If you have two routes with the same pattern, only the first one will be matched in the Router.
{
"pattern": "ZISOHSet/{objectId}",
"name": "object",
"target": ["object"]
}, {
"pattern": "ZISOHSet/{objectId}",
"name": "payobject",
"target": ["payobject"]
}
So in this case "object" will me matched. Change the patter of one of your routes and try again.
Furthermore, use navTo() when navigating:
this.getRouter().navTo("payobject", {
objectId: "MyParameterhere"
});
Instead of using
getTargets().display
Use method navTo from your Router object
https://sapui5.hana.ondemand.com/#/api/sap.ui.core.routing.Router/overview
You have to routes with identical patterns: "object" and "payobject", I would try to remove one and check again.

navTo only working for one page

I have a the following function in my controller file:
handleNavTo : function (oEvent){
var page = oEvent.getSource().data("navToPage");
var router = sap.ui.core.UIComponent.getRouterFor(this);
router.navTo(page);
}
So I don't have to write out a new function for each link, I'm using a data attribute in an XML view to pass in the page I want to navigate to, like this:
<StandardTile
title="{i18n>tileEmployees}"
press="handleNavTo"
data:navToPage="employees"
icon="sap-icon://employee"/>
<StandardTile
title="{i18n>tileProducts}"
press="handleNavTo"
data:navToPage="products"
icon="sap-icon://product"/>
I have the routing configured in a manifest.json file:
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"viewPath": "testApp.view",
"controlId": "app",
"controlAggregation": "pages",
"transition": "slide",
"bypassed": {
"target": "notFound"
}
},
"routes": [
{
"pattern": "",
"name": "appHome",
"target": "home"
},
{
"pattern": "products",
"name:": "products",
"target": "products"
},
{
"pattern": "employees",
"name": "employees",
"target": "employees"
}
],
"targets": {
"home": {
"viewName": "Home",
"viewLevel": 1
},
"notFound": {
"viewName": "NotFound",
"transition": "flip"
},
"products": {
"viewPath": "testApp.view.products",
"viewName": "ProductsSplitView",
"viewType": "JS",
"viewLevel": 2
},
"employees": {
"viewPath": "testApp.view.employees",
"viewName": "EmployeesSplitView",
"viewType": "JS",
"viewLevel": 2
}
}
My problem is that clicking on the tiles only works for the Employees page. I know the routing is configured correctly for the products page as I can type in the url in the address bar and it brings up the page: mydomain.com/#/products.
I get no errors, it just seems to silently fail. the data attribute value is being called correctly, if I console.log(page) in the controller function I get the correct value, so this has be stumped.
Any help would be appreciated.
i would guess that it does not find the route by name because you have a typo in the route config: "name:": "products", should be "name": "products",