Get yourself some live market data with UI5 visuals on your fiori tiles
Dear all,
After working the DesignStudio space for two years now, I got the chance to look into some Fiori topics lately. As a result I would like to share a Fiori component with you today, which enables you to render arbitrary UI5 content on a custom Fiori tile and ultimately tie that to any web service there is on the web.
For my examples I used the Yahoo finance API to get live market data. Yahoo offers extensive market data through a SQL based interface, which they call YQL (Yahoo Query Language).
UPDATE: Unfortunately Yahoo stopped the service after 9 years in late 2017 claiming it is violating their terms of services. I am currently migrating my code examples to iextrading instead.
Fig.1: Example usage of YQL with my custom tiles in combination with UI5 NumberContent MicroCharts and others
Generally speaking my custom tile type extends the standard Fiori dynamic tile exposing its content to the tile configuration screen. In order to be able to consume web services which are not within your domain I configured the AJAX calls to use jsonp.
You can add any UI5 content that fits the tile’s space. Just browse SAPUI5 explored and check the underlying XML-View code. Wrap that XML-snippet in a UI5 fragment-tag defining the necessary namespaces (e.g xmlns=”sap.suite.ui.microchart”) and you are good to go.
The service callback is added to a JSONModel so that you can use UI5 templates to feed the values into your custom tile dynamically during runtime. All examples used on the website use the yahoo finance API but you are not limited to that.
The custom tile ships with two shapes. The standard tile, which is a square (1×1) and the second option, which is a wide rectangle (2×1). For the latter you also get to choose if you want two columns for your visuals or one wide one. The tiles adapt slightly on mobile devices in total size to save space.
Fig.1: Another two by one tile example with YQL showing a wide chart
To finally use my component in your system, you need to register it as a “chip”. Directions on how to do this can be found on my GitHub page or on the link mentioned before.
According to the SAP Fiori community you can achieve a similar solution as of HANA SP09 with the standard Custom App Launcher tile type. However my solution does not involve programming object deployment or a HANA platform at all. Reading from external source due to the lack of jsonp would also be a problem with the custom app launcher.
So if you want to keep it simple, be as flexible on how you visualize web service data as possible and read data from where ever you want to, my tile type is the way to go.
Check out my GitHub page for installation hints and further documentation especially regarding the possible configurations.
Also I would like to thank David Garcia for lending me one of his many hands to get this up and running in no time. You are the best David!
As usual feel free to leave comments and ask lots of follow up questions.
Yours
Martin
The following links could also be of interest to you:
- https://blogs.sap.com/2017/01/28/how-to-create-custom-tile-types-for-onpremise-fiori-launchpad/
- https://blogs.sap.com/2016/08/23/create-and-use-custom-tile-type/
- https://help.sap.com/saphelp_nw74/helpdata/en/3f/f37eb5e28a4da5b5b152b036776c98/content.htm
My custom tile was inspired by this GitHub project.
Hi Martin,
thank you for sharing, great post!
regards
Gunter
Really cool. Helped me a lot in developing nice tiles.
Thanks for your effort,
Klaus
You are very welcome Klaus.
I am trying to use On-Premise-oData-Services. But the path-binding that I am using does not work.
http://<host>:<port>/sap/opu/odata/sap/ZUSERINFO_SRV/UserCollection/?$format=json
"d" : {
"results" : [
{
"__metadata" : {
"id" : "http://<host>:<port>/sap/opu/odata/sap/ZUSERINFO_SRV/UserCollection('Klaus')",
"uri" : "http://<host>:<port>/sap/opu/odata/sap/ZUSERINFO_SRV/UserCollection('Klaus')",
"type" : "ZUSERINFO_SRV.User"
},
"UserID" : "Klaus",
"FirstName" : "REINER",
"LastName" : "KLAUS",
"Email" : "REINER.KLAUS@AVANTUM.DE",
"Percentage" : "12",
"Country" : "FR"
}
]
}
}
<RadialMicroChart percentage="{path:'/d/results/0/Percentage', formatter:'.formatValueShortNumber'}" valueColor="#0080ff" />
</core:FragmentDefinition>
What would be the correct path information from your point of view?
Regards, Klaus
Hi Klaus,
I updated the component in January regarding on-premise OData calls. Are you on the latest version already? In order to update please run /UI2/INVALIDATE_CLIENT_CACHES on SE38 to refresh after chip deployment. Your model path looks correct.
Apart from that the formatter function in your example will not do anything for percentages due to its inherent number range (-100 / +100). You might want to think about applying a formatter for the valueColor though. My standard function formatIntValueColor follows the most straighforward approach for most cases by coloring negative in red, zero in grey and positive numbers in green. Feel free to add a function of your own by copying mine.
Let me know how it goes.
Kind regards
Martin
Hi Martin,
to ensure that I am using the newest version, I just copied your GIT-Repository again
into my WebIDE after deleting the old ones and then deployed them into a completely
new BSP-Application with separate CHIP.
Additionally I have executed the ABAP report you mentioned. However I still can not see
any results. As long as I do not set the path for binding, everything looks good.
Is the way the oData-WebService-URL has been defined, look good from your point
of view? If not can you maybe provide an example with a generic service, e. g. the
GWDEMO Service of SAP, available on every On-Premise-System?
Thanks in advance.
Kind regards,
Klaus
Hi Klaus,
So you are on the current version. Let's rule out some more potential problems. I checked your example xml and got encoding errors while pasting the copied content. But since you say the radial chart shows up without the service I believe this happens only on my end.
Another problem could be your URL. Browser prohibit calling data from other servers than the one hosting the calling website. There are a lot of ways to implement this nevertheless. You need to be calling an OData service on the gateway, which also hosts the app. If not you need to take that into account. Maybe even apply a relative url to be absolutely sure (e.g. /sap/opu/odata/sap/ZUSERINFO_SRV/UserCollection/?$format=json).
Also make sure the model path leads to a number and the formatter creates output as expected by the chart.
I tested your example with one of my custom odata services successfully. Let me know how it goes.
Kind regards
Martin
Hi Martin,
that just worked perfectly 🙂
I have now used a relative path and not an absolute one (full-qualified with host and port).
Additionally I have created a second oData-Service with an additional INT4-field instead
of trying to format strings to a numeric value.
After integrating both into my custom tile definition I was able to use the data of my
service in footer/subtitle as well as in the microchart as data series.
Thanks you so much for your great support and this really cool development!
Klaus
You are welcome Klaus. It is nice to hear you like it.
Hi Martin,
I am trying to get rid of the namespace.
This is because with the namespaces the files paths seem to be too long, so that if you are deploying the application to a Netweaver system as BSP, the file paths that are too long are getting mapped in the file UI5RepositoryPathMapping.xml. Within that xml, the files that have a too long file path are getting a technical ID mapped to the correct filename.
I want to get rid of that to not always have to lookup, which file is which one, because this is
laborious when working on the application.
To achieve this, I have exported the application and then replaced all occurrences of convista.com.demo. and convista/com/demo/ in all files with ''(nothing) and reimported (download and upload both with report /UI5/UI5_REPOSITORY_LOAD) the application under a new BSP-ID.
After doing the CHIP-Customizing and creating the new tile, I am able to do the generic tile
customizing. But when adding the tile to the Fiori-Launchpad, no data is getting displayed
at all, so something seems to be wrong, although I have doublechecked all occurences of
the namespace in all files.
So what needs to be done in addition, to have a shorter path / no namespace at all?
Thanks, Klaus
Hi Klaus,
The namespace is tied to the whole project structure, so you need to check also the configuration files in addition to the ui5 stuff.
It is possible that there is a namespace validation in place that requires at least three parts like sap.demo.com etc. I couldn't find the reference to back up my claim, though.
Let me add that I never had any path problems using relative urls.
Kind regards
Martin
Hi Martin,
thanks for that hint.
I have tried the following: Downloaded the application and Uploaded it again with a new BSP-ID. Just to test and to ensure that a downloaded and uploaded application still works. And it did.
Then I have changed the downloaded BSP:
- renamed the folder "convista" to "p" (to get it as short as possible)
- replaced "convista" in all files with "p" wherever this string occurred
Then uploaded the application again under a new BSP-ID. Unfortunately this does not work, although I have made a minimum adjustment for namespace.
Any idea?
Kind regards,
Klaus
Not specifically no. I can only suspect that there is still some file looking for another name. Did you check your browser's developer tools? All browsers show network calls as well as Javascript errors on the console tab. Have a look in there to pinpoint the problem better.
Maybe consider creating a new project with your desired namespace on WebIDE and copying the relevent code pieces to avoid nameing mistakes.
Kind regards
Martin
Hi Klaus,
Thanks for this blog, it's exactly what I need. After doing some research, I discovered that the new Fiori Launchpad 2.0 supports dynamic data binding for tiles. Is it possible to have dynamic data in Fiori Launchpad 1.0?
I was able to connect to the apiextrading.com api and storing the data in a model by implementing the following code in my Component.js onInit method: