Navigate to the same view but with a different parameters - sapui5

I'm trying to create a launchpad app using a list of tiles, the problem is that when I click in a tile it could be a app then I navigate to app url or it could be an group of apps or other groups than I need to navigate to the same view of the launchpad but with a new list of tiles. For now, I just want to navigate to navigate to the same view when I click in a tile and do it with slide transition but if I create a route with the same target of default route the view does not render when I start the application, it only works if I ser the target of the route when I create an other target with the same view name.
where is a part of my manifest:
"routes": [
{
"pattern": "",
"name": "group",
"target": "group"
},
{
"pattern": "group",
"name": "group2",
"target": "group2"
}
],
"targets": {
"group": {
"viewName": "TileGroup",
"viewLevel" : 1
},
"group2": {
"viewName": "TileGroup",
"viewLevel" : 2
}
}
}
ans here the controller of my TileGroup view for now.
sap.ui.define([
"sap/ui/core/UIComponent"
],
sap.ui.controller("pelissari.soficom.launchpad.controller.TileGroup", {
onInit: function() {
var oModel = new sap.ui.model.json.JSONModel();
oModel.loadData("./model/data.json");
this.getView().setModel(oModel);
},
onPress: function (oEvent) {
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.navTo("group2");
}
}));
With this code I think that the navigation is working because the url of the app changes when I click in a tile but the view do not change.

If you are seeing the URL being changed, then you have the first part of the solution ready. The only thing is that you shouldn't navigate to a new target. Instead, you should navigate to the same target, but passing another tilegroup identifier using the second parameter of the navTo method, e.g.:
oRouter.navTo("tileView", {group: "group1"});
The second part involves getting an event raised in your controller whenever the URL changes, so that you can act on the change.
To catch the ID passed using the navTo method, you should change the route pattern in your manifest accordingly, e.g.:
"pattern": "tiles/:group:"
tiles indicates a fixed part in your URL, while :group: specifies an optional parameter called group. If you want to do this from the root (I think that's what you planned to do), it should be
"pattern": ":group:"
To inform the router that you want to get triggered when the URL changes, you can set a call-back. You can do so by inserting the code below into the onInit handler of your controller:
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.getRoute("group").attachPatternMatched(this._onPatternMatched, this);
When this is in your onInit handler, the _onPatternMatched handler is invoked when there was a change in the URL that involves target group. The latter is useful, otherwise your method would get triggered for every URL change, even when the view linked to your controller is not visible.
From the _onPatternMatched method, you should read back what the group ID is that should be displayed, so that you can change the tiles. You can do this by reading the arguments parameter from the event parameter:
_onObjectMatched : function (oEvent) {
var groupId = oEvent.getParameter("arguments").group;
console.log("Group ID: " + groupId);
},
The essentials of routing are very well explained in the UI5 walk-through step 31, 32 and 33. Please especially take note of part 32, which explains routing with parameters.

Related

SAPUI5 Navigate to a view in same application by opening a new tab

I have a SAPUI5 application and I need to open a view (View2) by passing some query string parameters from another view (View1) by writing a method in View1 controller.
So far I've done it like below and it works fine when I run the application through webIDE. But when I deploy the application to the cloud platform it gives an error.
Controller js function
handleDetailNavPress: function(oEvent) {
var viewModel = this.getModel();
var headerInfo = viewModel.getProperty("/HeaderInfo");
var navUrl = "#detailscreen/params?docNo=" +
headerInfo.DocNo+ "&docName=" + headerInfo.DocName";
var url = window.location.href.split('#')[0] + navUrl;
//Navigate to second view
sap.m.URLHelper.redirect(url, true);
}
Routing settings in manifest
"routing": { "routes": [
{
"pattern": "viewone",
"name": "viewone",
"target": "viewone"
},
{
"pattern": "viewtwo/params:?query:",
"name": "viewtwo",
"target": "viewtwo"
} ],
Error I got after deploying
viewSample:112 Uncaught TypeError: Cannot read property '6' of null
at getIntentParameter (qcmanager:112)
at Object.requestSite (qcmanager:352)
at Object.getSiteJson (qcmanager:500)
at Object.loadAppSite (qcmanager:567)
at qcmanager:745
at qcmanager:746
What is the issue. Is there another way to navigate within same app by opening a new tab.
If you want to open a Vi 2 in new tabe there are two options:
Either crate a saperate inde.html for that new view and include that view in that index.html (It's basically will work like a saperate SAP UI5 application for user)
But i will not recomend this one
The other solution is
Instead of Using "sap.m.URLHelper", user:
window.open('[PAth to you Application index file]/[url]', '_blank');
For Example: window.open('https://www.mysapui5app/#podetailscreen/params?docNo=...', '_blank');
*Remember, _blank is madatory to open view in new tab.
When you deploy your application the launchpad the link changes, the second view comes like current URL + &/, so you need to check your URL and pass it correctly.
Just change these two variables accordingly:
navUrl
URL
Also, I would suggest to do cross app navigation as it will be more safer.

Passing Data Between Controllers While Navigating

I want to pass data between two controllers (in addition to routing parameters) and I would like to know the correct way to do this.
For example: when I navigate to pattern /order/{id}, I do this in the view controller:
this.getRouter().navTo("order", {
id: sOrderId
});
I want to pass additional JSON object which I don't want to be part of routing parameter.
What should I do in this case?
--edit
Wanted to add what I like to achieve with this
I want pass data from master to detail. Both master and detail page has individual routing patterns assigned. So user can land on master or detail directly. When they land on master - user can choose bunch of detail items, and navigate to first detail item, and from there navigate to other items he/she selected earlier on master. So what I want to pass is this selection from master controller to detail controller.
Note: If the intention is to pass selected keys from the main view to the detail view, see https://stackoverflow.com/a/48870579/5846045 instead.
Using a client-side model
Usually, data are stored separately in models instead of assigned to local variables and passing them around. Model data can be then shared with anything that can access the model (e.g. View for data binding).
Here is an example with a client-side model (JSONModel):
Create a JSONModel which is set on a parent ManagedObject. E.g. on the Component via manifest.json:
"sap.ui5": {
"models": {
"myModel": {
"type": "sap.ui.model.json.JSONModel"
}
}
}
In the controller A, set the object to pass before navigating:
const dataToPass = /*...*/
this.getOwnerComponent().getModel("myModel").setProperty("/data", dataToPass, null, true);
In the controller B, do something with the passed data. E.g. on patternMatched handler:
onInit: function() {
const orderRoute = this.getOwnerComponent().getRouter().getRoute("order");
orderRoute.attachPatternMatched(this.onPatternMatched, this);
},
onPatternMatched: function() {
/*Do something with:*/this.getOwnerComponent().getModel("myModel").getProperty("/data");
},
Using NavContainer(Child) events
There are several navigation-related events such as navigate,
BeforeHide, BeforeShow, etc. which contain both views - the source view (from) and the target view (to).
You can make use of the API data to pass the data.
Here is an example:
In the controller A:
onInit: function() {
this.getView().addEventDelegate({
onBeforeHide: function(event) {
const targetView = event.to;
const dataToPass = /*...*/
targetView.data("data", dataToPass);
}
}, this);
},
In the controller B:
onInit: function() {
this.getView().addEventDelegate({
onBeforeShow: function(event) {
/*Do something with:*/this.getView().data("data");
}
}, this);
},
See also the related documentation topic: Passing Data when Navigating
You can create a local model (usually a JSONModel) and set it to inside your app Component.
// inside Component.js
var model = new sap.ui.model.json.JSONModel({ foo: “bar”});
this.setModel(model);
Inside each controller you can use
var model = this.getOwnerComponent().getModel();
console.log(model.getProperty(“/foo”));

Hiding UI element from fragment.xml in standard App

I want to hide few UI elements from My Travel and Expense (Standard App). I have tried in different approaches but I am not able to achieve what i want. Here is my requirement:
In My Travel and Expense App (TRV_TE_CRE), I want to hide the following UI elements:
GenericClaim.fragment.xml - Button id="costAssignmentButton"
I have added the extension project for TRV_TE_CRE and tried as below:
In component.js I added the following statement to hide
customizing:
{
"sap.ui.viewModifications": {
"mytravelandexpense.view.GenericClaim": {
"costAssignmentButton": {
"visible": false
},
},
},
Result: not working
Extended the GenericClaim.controller.js:
I added the below code in hookmethod
this.byFragmentId("costAssignmentButton").setVisible(false);
Result : whole claim page is not loading
By using access key I have commented the UI code in GenericClaim.fragment.xml
Result : not getting hide
Instead of the fragment ID, you can access the element ID from the view. Add this method in your view controller.
onAfterRendering : function(){
var buttonToHide = this.getView().byId("costAssignmentButton");
buttonToHide.setVisible(false);
},

Get passed data on next page after calling "to" from NavContainer

I am on my way building a Fiori like app using SAPUI5. I have successfully built the Master page, and on item click, I pass the context and navigate to Detail page.
The context path from Master page is something like /SUPPLIER("NAME"). The function in App.controoler.js is as follows:
handleListItemPress: function(evt) {
var context = evt.getSource().getBindingContext();
this.myNavContainer.to("Detail", context);
// ...
},
But I would like to know how I can access this context in the Detail page. I need this because I need to use $expand to build the URL and bind the items to a table.
There is an example in the UI5 Documentation on how to deal with this problem using an EventDelegate for the onBeforeShow function which is called by the framework automatically. I adapted it to your use case:
this.myNavContainer.to("Detail", context); // trigger navigation and hand over a data object
// and where the detail page is implemented:
myDetailPage.addEventDelegate({
onBeforeShow: function(evt) {
var context = evt.data.context;
}
});
The evt.data object contains all data you put in to(<pageId>, <data>). You could log it to the console to see the structure of the evt object.
Please refer the "shopping cart" example in SAP UI5 Demo Kit.
https://sapui5.hana.ondemand.com/sdk/test-resources/sap/m/demokit/cart/index.html?responderOn=true
Generally, in 'Component.js', the routes shall be configured for the different views.
And in the views, the route has to be listened to. Please see below.
In Component.js:
routes: [
{ pattern: "cart",
name: "cart",
view: "Cart",
targetAggregation: "masterPages"
}
]
And in Cart.controller.js, the route has to be listened. In this example, cart is a detail
onInit : function () {
this._router = sap.ui.core.UIComponent.getRouterFor(this);
this._router.attachRoutePatternMatched(this._routePatternMatched, this);
},
_routePatternMatched : function(oEvent) {
if (oEvent.getParameter("name") === "cart") {
//set selection of list back
var oEntryList = this.getView().byId("entryList");
oEntryList.removeSelections();
}
}
Hope this helps.

Chrome Extension - Duplication of the event listener?

Introduction
I've got a problem with my extension for Chrome. It supposed to show a small overlay popup window (created in jQuery) with search results from google based on your text selection. Basically you should be able to highlight a text on any page, right click on it (context menu), click on "Search for 'selected keyword'" and a small window pops up in the same tab as an overlay with all search results from google or different search engine.
The problem
Now the extension works really well and without problems, HOWEVER after extensive using of this extension (let's say 1 hour) when I'll highlight another keyword and search for it, extension REMEMBERS last keyword and shows wrong search results. Then again, when I'll highlight another keywords it rememebrs the keyword I've just highlighted but previously didn't get the results for it. It's like a chaining process and I'm always one keyword behind.
My thoughts
I think that the cause of this problem might be event listeners, because when this problem occurs I've got a log from console.log(chrome.extension.onRequest.hasListeners()); which says true. It means that there are 2 or more event listeners attached and they shouldn't as I'm removing them by chrome.extension.onRequest.removeListener(listener1);
Maybe it happens when the actual web page is still loading and I'm highlighting keyword, clicking on context menu and extension can't load yet but somehow event listeners firing... I really can't fully replicate this problem... and what causes this problem.
Manifest File
{
"name": "Search Accelerator",
"version": "1.0",
"manifest_version": 2,
"description": "Search Accelerator extension",
"icons": {
"16": "icon19.png",
"48": "icon48.png",
"128": "icon128.png"
},
"background": {
"scripts": ["content_script.js"]
},
"minimum_chrome_version": "18",
"permissions": [
"contextMenus",
"tabs",
"http://*/*",
"https://*/*",
"management",
"webRequest"
]
}
Content Script
chrome.contextMenus.create({ "title": 'Search for "%s"',
"contexts":['selection'], "onclick": getClickHandler() });
function getClickHandler() { return function(info, tab) {
console.log(chrome.extension.onRequest.hasListeners());
chrome.extension.onRequest.addListener(function listener1 (request, sender, sendResponse) {
var url = "http://www.google.com/?s=" + info.selectionText;
console.log(url); var keywordObj = {keyword: url};
if (request.keywordRequest == "Yes") {
console.log(keywordObj);
sendResponse(keywordObj);
};
chrome.extension.onRequest.removeListener(listener1); } );
chrome.tabs.executeScript(null, { file: "jquery.js" }, function() {
chrome.tabs.executeScript(null, { file: "popup.js" });
}); }; };
Popup js
chrome.extension.sendRequest({keywordRequest: "Yes"}, function(response) {
$(document).ready(function() {
if($("#e14_accelerator")) {
$("#e14_accelerator").remove();
}
var rkeyword = response.keyword;
$("body").append("<div id=\"e14_accelerator\" style=\"position: fixed;top: 30px;right: -330px;z-index: 999999; \"><iframe style=\"border:5px solid #c9c9c9;-webkit-box-shadow: 1px 1px 15px 1px rgba(0, 0, 0, 0.2);\" src=\""+ rkeyword +"\" width=\"328\" height=\"240\"></iframe></div>");
$("#e14_accelerator").animate({right:-13},500);
$(document).click(function() {
$("#e14_accelerator").remove();
});
$("#e14_accelerator").click(function() {
return false;
});
});
});
Error messages that appear when this problem occur:
Error during tabs.executeScript: Cannot access contents of url "chrome-devtools://devtools/devtools.html?docked=true&dockSide=bottom&toolbarColor=rgba(230,230,230,1)&textColor=rgba(0,0,0,1)". Extension manifest must request permission to access this host. sendRequest:21
chromeHidden.handleResponse sendRequest:21
Error during tabs.executeScript: Cannot access contents of url "chrome-devtools://devtools/devtools.html?docked=true&dockSide=bottom&toolbarColor=rgba(230,230,230,1)&textColor=rgba(0,0,0,1)". Extension manifest must request permission to access this host. sendRequest:21
chromeHidden.handleResponse