Why Is My Main Controller Being Called Twice? - sapui5

All other routings are fine, but for some reason the main controller is being called twice. Why would this happen?
onInit: function() {
var oRouter = this.getOwnerComponent().getRouter();
oRouter.getRoute("main").attachMatched(this._onRouteMatched, this);
this.getView().setModel(new JSONModel({
Jobs: []
}), "job");
},
Is this down to the routing config?
"rootView": {
"viewName": "CompleteSurvey.view.Main",
"type": "XML"
},
"routing": {
"routes": [{
"name": "main",
"pattern": "",
"target": ["main"]
}],
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"viewPath": "CompleteSurvey.view",
"controlId": "app",
"controlAggregation": "pages"
},
"targets": {
"main": {
"viewName": "Main"
}
}
}

The reason why your Main controller is created twice is because its view is created twice.
Your Component fetches manifest.json and looks at the rootView to create the assigned view ("CompleteSurvey.view.Main").
Your router gets initialized, sees that the current hash / pattern is "", and creates the corresponding view which is the "Main" view again.
The current best practice is to have a separate root view. You can keep the Main for the "" pattern, but avoid using the same view again as a root view.
For further references, take a look at the tutorial Navigation and Routing and this answer.

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.

Problem with Routing from one view to the other in SAPUI5

I have been trying to route from View1 to View2. My code is the same as what is given in the SAPUI5 SDK, with some minor changes according to my project. I tried multiple solutions given on the internet but none of them worked.
View1.controller.js
onNav: function (oEvent) {
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.navTo("View2");
//return this.getOwnerComponent().getRouter().navTo("View2");
},
manifest.json
"routes": [
{
"pattern": "",
"name": "View1",
"target": "View1"
},
{
"pattern": "View2",
"name": "View2",
"target": "View2"
}
],
"targets": {
"View1": {
"viewId": "View1",
"viewName": "View1"
},
"View2": {
"viewId": "View2",
"viewName":"View2"
}
}
The error shown is:
sap.ui.core.UIComponent.getRouterFor is not a function
Double check if you have the following:
1) Router class declared in the routing configuration of the manifest.json file:
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
},
"routes": [
]
2) Router was initialize. This is almost always done inside Component.js:
init: function () {
// call the base component's init function
UIComponent.prototype.init.apply(this, arguments);
// enable routing
this.getRouter().initialize();
},
3) Check if this inside your onNav method is your controller.
For that, you can add a breakpoint inside it, open the browser console use the following call:
this.getMetadata()
Use the sap.ui.core.UIComponent.getRouterFor(this) inside a controller onInit method. You should get the reference for the router at that point.

Sapui5 Router is not working for the second time in Master Detail App

Hello Everyone,
Im facing an issue in Routing in Master Detail Application. When im clicking on Master Record for the first time. It is redirecting to Detail View. But if i click on another record in Master View, Router is not navigating to Detail View..
Can some one help me to clear my issue ??
If you see the above pic, When i hit on First Record corresponding details are loaded in Detail View.
If i hit on second Record(highlighted in Red) my Detail page is not getting triggered.
Below is the code im trying...
Master.controller.js
onItemPress: function (oEvent) {
var contextPath = oEvent.getParameter('listItem');
var getPath = contextPath.getBindingContext("masterModel").getPath().split("/")[1];
sap.ui.getCore().selRecordData = contextPath.getBindingContext("masterModel").getModel().getData()[getPath];
this._router.navTo("detail");
},
Detail Controller.js
onInit: function () {
var oComponent = this.getOwnerComponent();
this._router = oComponent.getRouter();
this._router.getRoute("detail").attachPatternMatched(this._routePatternMatched, this);
},
_routePatternMatched: function () {
var detailModel = new sap.ui.model.json.JSONModel();
detailModel.setData(sap.ui.getCore().selRecordData);
this.getView().setModel(detailModel, "detailModel");
}
manifest.json
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"async": true,
"viewPath": "sap.m.serviceRequestLast.view",
"controlAggregation": "pages",
"controlId": "idSplitApp",
"clearControlAggregation": false
},
"routes": [{
"pattern": "",
"name": "master",
"target": [
"detail",
"master"
]
}, {
"pattern": "detail",
"name": "detail",
"target": [
"master",
"detail"
]
}
],
"targets": {
"master": {
"viewName": "Master",
"controlAggregation": "masterPages",
"viewLevel": 1
},
"detail": {
"viewType": "XML",
"transition": "slide",
"clearAggregation": true,
"viewName": "Detail",
"controlAggregation": "detailPages",
"viewLevel": 2
}
}
}
Can some one please help me to sort my issue..
Thank you in advance..

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.