How to change FLP - Parameter within the same app - sapui5

I have an app with two tiles on the Fiori Launchpad, setting a URL parameter to differ. I result in having following two Hashes :
#SemanticObject-action?myparam=tile1&/inner/app/path
#SemanticObject-action?myparam=tile2&/inner/app/path
Now I want to navigate from one tile to the other.
In the Component.js I get that parameter:
this.getComponentData().startupParameters.myparam[0];
and so I can decide how it has to act.
Now how to change that param at a controller? I tried (what did not work):
//simply overwriting does not work
this.getComponentData().startupParameters.myparam[0] = "tile2";
sap.ushell.Container.getService("CrossApplicationNavigation").toExternal(
{params : {myparam: "tile2"}});
What I do not want is using things like window.location, regex for replacement of "tile1" with "tile2" or such inproper solutions.
window.location.hash = window.location.hash.replace(sOldParam, sNewParam);

Related

Multiple values for the 'scope' property in a manifest.json file.

I am working on an existing application with legacy code base. While I would love to see the entire app converted to a PWA some day, for now my plan is one page (one url) at a time. For this, I know that the "scope" property is going to be my best friend for some time. While I can pass "." as a value to the property and treat all the routes as PWS, but as I mentioned earlier, that's not the plan. Hence, below is not an option for me.
{
"scope" : "."
}
For now, I plan on covering only two routes under the PWA scope, "list page" and the "details page". Hence I would have preferred something like below to work, but it did not.
{
"scope" : [
"/list",
"/id/details"
]
}
Any suggestion(s)?
The scope member is a string that represents the navigation scope of this web application's application context.
https://w3c.github.io/manifest/#scope-member
It will not support an array of multiple values.
An option would be to use the scope /pwa/ (or similar) and as you migrate sections of the app redirect /list to /pwa/list, etc.

Fiori -- Cross application navigation; Handling startup parameters?

This question is related to:
Fiori - Cross Application Navigation
http://help.sap.com/saphelp_uiaddon10/helpdata/en/07/9561b716bb4f2f8ae4e47bacbdb86d/content.htm
Remove URL params on routing
My use case is like this:
I have multiple applications that should link to others (deep).
Since documentation of cross navigation mention to avoid deep links I decided to use a startup parameter.
For example:
Application A has a list of some items in the detail view of one item there is a reference to another application B that contains some other details.
Assume A shows article details and B shows some details of a producer of an article.
Application A would now use some navigation like this:
sap.ushell.Container.getService("CrossApplicationNavigation").hrefForExternal({
target : { semanticObject : "ApplicationB", action : "display" },
params : { "someID" : "102343333"}
})
Now in application B I use code like this inside the Component.js at the end of the init method.
var oRouter = that.getRouter().initialize();
var oComponentData = this.getComponentData();
if (oComponentData.startupParameters) {
oRouter.navTo("SomeView", {
someId : oComponentData.startupParameters.someID[0],
}, false);
}
First question: Is this the right place for handling the startup parameters?
Second question: If I using the navigation the startup parameter will still be in the code, I would prefer to remove it, but how?
Update
In the target application (B) it would lead to the following URL:
https://server/sap/bc/ui5_ui5/ui2/ushell/shells/abap/FioriLaunchpad.html?sap-client=100&sap-language=EN#SemObject-display?someID=102343333&/SomeView(102343333)/
Anyhow I would prefere to have something like this:
https://server/sap/bc/ui5_ui5/ui2/ushell/shells/abap/FioriLaunchpad.html?sap-client=100&sap-language=EN#SemObject-display?/SomeView(102343333)/
The parameter must be retrieved as
var oComponentData = this.getComponentData();
if (oComponentData.startupParameters) {
oRouter.navTo("SomeView", {
someId : oComponentData.startupParameters.someID[0],
}, false);
as you write. In Fiori applications, the startup parameters injected into the Component data of your constructor may have been renamed, enriched by further default values etc.. Thus they may be distinct from the parameter one observes in the url. Applications are advised to refrain from trying to inspect the URL directly.
If one supplies a very long set of url parameters, one will observer that the FLP replaces some of them with sap-intent-param=AS123424 ("compacted URL") to work around url length restrictions on some platforms and in bookmarks, in the
getComponentData().startupParameters one will receive the full set of parameters).
As to the second question.
No, there is currently no way to "cleanse" the URL and avoid the redundancy between and inner app route.
SemObject-display?someID=102343333&/SomeView(102343333)/
which after navigation may look like
SemObject-display?someID=102343333&/SomeView(102343999)/
App was started with 102343333, but then user navigated within the app to another item (102343999).
Any change in the "Shell-part" of the has (SemObject-display?someID102343333) will lead to a cross-app-navigation (reinstantiation of your component) with a different startupParameter.
(There are cases where this is desired in the flow, e.g. a cross navigation from a OrgUnit factsheet to the parent OrgUnit factsheet via a link).
There were ideas within SAP to fuse the inner-app routes and the intent parameters, but they were not carried out, as it's mostly url aesthetics.
Note: To support boomarking, one has to respect both startup parameters and
inner app route during component instantiation,
assuming the user created a bookmark on
SemObject-display?someID=102343333&/SomeView(102343999)/
(While he was looking at 9999(!)).
When reinstantiating the app, the inner app route should take higher precedence than startup-parameters.
So amend the code to:
var oComponentData = this.getComponentData();
if (oComponentData.startupParameters) {
if (sap.ui.core.getHashChanger().getHash()=== "") {
// if no inner app route present, navigate
oRouter.navTo("SomeView", {
someId : oComponentData.startupParameters.someID[0],
}, false);
}
}
https://sapui5.netweaver.ondemand.com/#docs/api/symbols/sap.ushell.services.CrossApplicationNavigation.html
SAP Fiori Launchpad for Developers, Navigation Concept
http://www.sdn.sap.com/irj/scn/go/portal/prtroot/docs/library/uuid/907ae317-cb47-3210-9bba-e1b5e70e5c79?QuickLink=index&overridelayout=true&59575491523067
I was having issues navigating from a Fiori elements app in to a deep page in a freestyle UI5 app and then answer from #user6649841 provided most the solution for my requirement.
In my instance, navigating from the elements list report (app "A") in to the target freestyle app (app "B") I didn't want the worklist/initial page in app B to display at all and instead go straight to the detail page without a flickering of the initial app screen.
The below worked for me, note though it doesn't solve the ugly URL issues. In my case I'm not fussed about it as my nav back will nav back to the elements list report (App A) and never show the worklist page in App B so the user will never make another search on top of this URL which would lead with inconsistent inner and outer keys
Component.js (at end of init function after all the standard sap code, but before router initialization):
var oComponentData = this.getComponentData();
var startupParams = oComponentData.startupParameters;
if (startupParams && startupParams.myQueryStringParamName && startupParams.myQueryStringParamName[0]) {
//In my case using hash changer as I dont want the original landing page (default route) to be
//in the history, so the detail page loads straight away and nav back will cause to nav back to App A
var hashChanger = sap.ui.core.routing.HashChanger.getInstance();
hashChanger.replaceHash("detailPage/" + startupParams.myQueryStringParamName[0]);
}
//initialise after the above so the new hash is set and it doesnt initially load the
//page assigned to the default route causing a flickering and nav slide effect
this.getRouter().initialize();
Looking at the UI5 SDK in UI5 1.48 and above in the initialize method of router you can pass in a boolean to tell it to ignore the initial hash so possibly can do a simpler implementation in newer releases of UI5
Is Component.js right place for handling the startup parameters?
Depends,if you have multiple views and you want to dynamically route based on the incoming parameters. Else you can handle in specific view also.
Your second question was not quite clear to me.
Nevertheless, if you want to only specific cases of startup parameters, then from Source App, set some flag to understand where is the request coming from and handle accordingly. So this way, your normal navigation won't be tampered.

Accessing value by javascript Play Framework/Scala

First of all I am using Play framework with scala.
I am creating a graph and with the node id I would like to show some information at the same page.
In order to do that, first I need to get node.name but for some reasons #node.name function is not working. When searching for it I learnt that it's because play is server-side and js is client-side. However I need to get the data somehow.
I also cannot access:
var html = "<h4>" + node.name + "</h4><b> connections:</b><ul><li>"
How can I access this through the view?
My second question is after reaching the js node.name, I need to access to controller and do the same action one more time but this time with the new node.name .
View Part:
onClick: function(node) {
#node.name
}
1) Is this code in your controller? And are the node variable in scope? If so this should be perfectly legal code, since it will be evaluated as pure scala.
2) The templates are a different story however. You probably know they parse everything as normal html, unless escaped. To use a variable you have to bring it into scope by either:
defining a 'constructor' for the template at the absolute beginning of the file:
#(node : Node)
...
#node.name // later in the file
See http://www.playframework.com/documentation/2.0/ScalaTemplates
or define a variable inside the template:
#defining( Get.node.from.somewhere ) { node =>
#node.name
}
See Play! framework: define a variable in template?
If you did either of the two, you should have no problem accessing the node variable. Even in scripts. But note that external scripts does not have access to the same variables. It is thus very common to use inline scripts or import it as another template if you need to access a variable from JavaScript.
Edit: I've made a gist of a template, controller and routes file: https://gist.github.com/Jegp/5732033

Zend Framework / Form Element is rendering as a text box rather than a dropdown box

I have the following in a config.ini file: (Zend_Form_Element)
site_status.name = "site_status"
site_status.type = "select"
site_status.label = "Status"
site_status.options.multiOptions.active.key = "Active"
site_status.options.multiOptions.active.value = "Active"
site_status.options.multiOptions.active.key = "Inactive"
site_status.options.multiOptions.active.value = "Inactive"
As you can see this is supposed to be a dropdown (select) box, however it is being rendered as a standard text box. What am I doing wrong?
--> Edit
Rather than tying the elements to a form, I am trying to tie them to a database: In my code it would look something like this:
[{tablename}] // the table name would represent a section in the ini
{column}.name = "{column_name/form_field_id}";
{column}.type = "{form_element_type}"
{column}.label = "{form_element_label}"
...
From there I would pull in the database table(s) that the form would represent data for (one or more tables as necessary). As far as the reasoning for this approach is that (down the road), I want to define (either by ini or some other storage method), a configuration file that would be a list of fields/elements that belong to a specific form (that a non-programmer type could easily edit), that the 'generic' form class would read, pull in the element info, and create the form on the fly.
I do realize however this poses another problem which I haven't yet figured out, and that is how to use table lookups for select elements (without coding the database retrieval of the lookup into the form, so that a non-user could easily just define it without any programming, purely configuration, but that is a whole other topic not part of my question here. (and I think I have viable ideas/solutions to that part of the problem anyhow) -- extra config entries and a generic routine pretty much.
I hope that clarifies my thought process and reason why I am doing it the way I am in the example above.
I have not yet played with using a Zend_Config to construct an instance of Zend_Form.
But a look at the code suggests that Zend_Form::addElement() doesn't directly take a Zend_Config instance as a param. Rather, it looks like you need pass your Zend_Config instance to the form constructor. It also seems that the config format needs to be a little deeper in order to map config keys to setXXX() calls.
In path/to/config/myForm.ini:
[myForm]
myForm.elements.site_status.name = "site_status"
myForm.elements.site_status.type = "select"
myForm.elements.site_status.label = "Status"
myForm.elements.site_status.options.multiOptions.active.key = "Active"
myForm.elements.site_status.options.multiOptions.active.value = "Active"
myForm.elements.site_status.options.multiOptions.inactive.key = "Inactive"
myForm.elements.site_status.options.multiOptions.inactive.value = "Inactive"
Then instantiating:
$formConfig = new Zend_Config_Ini('path/to/config/myForm.ini', 'myForm');
$form = new Zend_Form($formConfig);
Not tested, but looking at this example:
Using Zend_Form with Zend_Config - Andrew Vayanis
it feels like it should go something like the above.
Update
In view of the comments/feedback from #Aaron, two more approaches.
We could extend Zend_Form, implementing a method called something like addElementByConfig in which we would pass the shallow Zend_Config instance that describes the element itself. In fact, we could even just override addElement(), taking a recursive approach: if the first param is an instance of Zend_Config, then call addElement() using the component data.
If the atomicity and re-usability are the primary benefits we seek in using Zend_Config to describe an element, then perhaps we just make a custom element extending Zend_Form_Element. Then we could use these elements in any forms we wish.

Rewrite Route to map to default route

Because of the problems I experienced here: Zend_ Controller_ Router_Exception: “xyz” is not specified
I want to have this route:
":module/:controller/:id"
and map it onto this:
":module/:controller/:action/id/$id"
Is there any possibility to do this with Zend Framework? I do not want to forward the browser to that URL. I just want to tell Zend Framework how to handle this route.
As for reasons why I would like to do this, you can find them in that linked SO question.
Yes it is possible. In my application.ini I specify my routes using regex this way:
resources.router.routes.something.type = "Zend_Controller_Router_Route_Regex"
resources.router.routes.something.route = "mymodule/mycontroller/([0-9]+)"
resources.router.routes.something.defaults.module = "mymodule"
resources.router.routes.something.defaults.controller = "mycontroller"
resources.router.routes.something.defaults.action = "myaction"
resources.router.routes.something.map.1 = "id"
I am not familiar with the ":variable" way of defining routes, but you can take from my example the ability to set default controllers, modules, and actions, without the need to explicitly define them in the url.