Intro
Every once in a while, you may find yourself wanting to stretch the visual limits of SAPUI5. Luckily, SAPUI5 provides the option of using other controls libraries. In principle, this should be fairly straight-forward. Some of the 3rd party control libraries are even built on JQuery, and thus share the same foundation as UI5. Including them in your UI5 app should in principle be easy.
In real life, however, most such third-party control libraries need some tweaking in order to be seamlessly integrated in a UI5 environment. This is particularly true when working with XML views, which is the preferred way of creating UI5 applications. XML views in SAPUI5 can have some “quirky” consequences on the related controller Javascript code needed for third-party controls. Also, the fact that most of the documentation for the main third-party control libraries refer to Javascript views, not XML, can pose interesting challenges.
This blog aims to provide a walkthrough of challenges and pitfalls related to using controls from the Kendo UI framework in SAPUI5. I will focus on some simple chart implementations, and show how to use these in XML views. Also, I will show how to feed remote data into the chart controls, using OData.
Note: some of the code screenshots may be difficult to read; please click them in order to enlarge!
Preparations
The following example has been created using the Web IDE on the HANA Cloud Platform – HCP. In the Web IDE, select New->Project from template->SAPUI5 Application. This gives you a simple UI5 application with one view (which should be of type XML).
The next step is to import the CSS and Javascript libraries into the application. Using references to content on the web is not recommended, as this might result in cross-domain errors under certain circumstances (such as when running your app from a Fiori Launchpad).
This is the folder structure with the Kendo JS and CSS libraries:
Creating the simple app
We’ll create a simple app based on a sample OData service, and implement a Kendo chart control to visualize the data. The Kendo chart control provides a wide range of different chart types; I will show a couple of these. The functionality is similar – once you implement one, you can easily switch to another.
The OData service resides on a Netweaver Gateway system. For the purpose of illustration, I have created a simple table that shows the distribution of zombie observations across the US. (Another distinct advantage of using zombies is the fact that zombie starts with the letter “Z”, which makes it particularly useful for creating custom SAP objects like “zombietable”.)
The OData service based on my zombie table is created in the Gateway Builder (transaction SEGW). This is outside the scope of this blog; there’s an excellent book from SAP Press dealing with these topics.
The resulting metadata of my OData service (extract):
And part of the resulting ZombieSet record set:
With our OData service set up and running, it’s time to do the fun stuff: the Kendo in UI5 application.
The UI5 application
As mentioned, I started by using the Web IDE wizard to create a simple UI5 project. The wizard provides the folder structure we need for our app, and we can also ask it to generate the first view (which should be of type XML). The advantage of XML views is that it forces us to adhere to the MVC pattern, unlike Javascript views which literally allows for any kind of Javascript functionality to be embedded into the view code. (Don’t use Javascript views, use XML! Grown-ups never use Javascript views!!)
If we follow the wizard’s recommendations, we’ll end up having one initial view called “View1” with a related controller.
I already mentioned the need for importing the Kendo CSS and Javascript files into their specific folders (the existing css folder for the CSS files, and Kendo JS files into a specific folder). When this is done, we need to register these in the manifest.json file:
The manifest.json file is a JSON model which acts as the “repository” of resources for our application. It should already contain a reference to the UI5 css file (css/style.css); all we need is to add the remaining Kendo CSS references, and also a specific section for the Kendo Javascript files as seen above. By doing this, there is no need to make references to these resources in the index.html file.
Our XML view file will be quite simple. All it contains is a “div” element which holds our Kendo chart (and another div to encapsulate it). This is the code:
That’s it – really. I promise the controller will be a bit more complicated!
Kendo source code
In order to include a Kendo UI control, we need to embed some Kendo Javascript code into our view controller. The Kendo UI site contains sample code for all of the Kendo controls. Ideally, all we would have to do is copy the code related to “our” control (the Kendo chart in our case) and paste it into our view controller. However, there are two major hurdles waiting for us: the fact that we’re using XML views, and that Kendo controls only work with JSON data. Since we’re in an SAP environment, we’re of course using OData, and as already mentioned we also decided to stick to XML views.
Both of these hurdles require some tweaking of the Kendo code.
Let’s look at the standard Kendo code for a bar chart:
This is an excerpt. As we can see, the data source here is a JSON model. This will not work for us; we receive our remote data in OData format, and what we need to do is convert this into JSON.
Luckily, this is easy enough with SAPUI5 – we’ll see that in a minute.
Here is the controller code, section by section.
The main part here contains the onAfterRendering method. This is where we invoke the Kendo script – we do this after SAPUI5 has finished the general rendering of the view, that is, built all the standard UI5 framework elements.
We start by declaring our OData service url, and the path to the relevant record set within this service.
We then define a variable for the OData model.
Then, we set the scope variable that equal to this. “this” is a reference to the current scope, or “where we are now” in layman’s terms. By defining a new variable “that” and aligning it with “this”, we can refer to the createChart function inside the “success” callback function for our oDataModel.read logic. OK, this might seem complex (as promised), but the main idea is that we need to keep a reference to “where” we can retrieve the createChart function. Without using the “that” variable, we will loose sight of it within the “success” function, since we will have another scope there – “this” will not refer to the context where createChart is defined anymore.
It’s a bit like going through a wormhole to another universe, and trying to find Andromeda by looking at the sky. Won’t work. By declaring “that” before going, and taking it with you, you won’t be lost.
What goes on inside the “success” function – which is only invoked if the read of the OData model succeeds – is that we call the createChart function (I’ll get to it in a minute), then invoke a couple of Kendo-related commands that adds attributes to the finished chart.
The next part of our controller contains the actual Kendo chart function:
This is almost a copy/paste of the code from the Kendo samples site. The only things changed are the variable names (ZombieNumber and ZombieCity, from our OData model), as well as the “selector” – which actually warrants a section of its own. Finally, the specification of our data source and schema, which is also explained in detail below.
Use of selectors in Kendo code
Kendo JS is based on JQuery, and uses “selectors” in order to identify page elements. Selectors are a key concept in JQuery (and thus SAPUI5) – this is worth reading up on. As in "the following section won't make much sense if you don't know what a selector is". I've provided a link to some excellent info further down.
Anyway, this whole selector thing poses a specific challenge when working with SAPUI5 XML views. In these views, the element id’s are “amended” by SAPUI5 on rendering. What happens is that the view name is added as a prefix to the element id, in order to uniquely define elements across views. Here is an example:
In our Kendo chart, the “div” element is named “chart”, as seen below:
What happens if we simply paste the standard Kendo Javascript code into our controller – with a selector “chart”? Let’s look at how the sample Kendo code appears:
This is the start of the createChart function, as retrieved from the Kendo sample site. As we can see, the function starts by using a selector identifying the “chart” element in our XML page. What happens if we use the code with the selector “as-is”?
The chart will not appear. This is because of the re-naming of our div element by the SAPUI5 rendering. If we look at the debugger, we can expand the elements to find our div:
As can be seen, SAPUI5 prefixes the element id with two underscores, followed by the view name (which, by the way, does not correspond to the actual view name as given by us; SAPUI5 generates brand new view names following the convention “xmlviewN”, where N is a number starting with 0), then two dashes, then finally our given id for the chart. Thus, “chart” in “View1” becomes “__xmlview0—chart”.
What we need to do, is tweak the Kendo code to correspond to the “new” naming done by SAPUI5. By altering the above selector slightly, we can make it look for all “div” elements containing the string “chart”:
Note that I am also passing our JSON “myData” to the function – this is my JSON model as derived from the original OData service. The main thing here is that the selector now works also in an SAPUI5 XML content.
More info on JQuery selectors and how to build them can be found here:
http://www.w3schools.com/jquery/jquery_ref_selectors.asp
Data provisioning - stuffing our charts with zombies
Kendo UI controls work with static, local or remote data. Static in this context means hard-coded values in the Javascript code for the Kendo control. This is usually not too interesting from an SAPUI5 point of view.
Local data relate to locally defined JSON models. This also amounts to hard-coding for mockup scenarios, and is also not very interesting for “real” applications.
Our example works with remote data – provided by a Gateway OData service. For use in the Kendo controls, the data will have to be in JSON format. Because of this “limitation”, we translated the data to JSON format when reading the OData service.
One issue with this way of providing JSON data from an OData source is that the Kendo code has issues with “complex” data models, such as the ones provided by OData-to-JSON conversion. If we simply declare our chart by copying and pasting the generic Kendo sample code, like most exampoles found on the site (related to JSON models) we may run into problems.
Running “standard” Kendo chart code will easily result in the following error:
This is due to the relative complexity of our JSON data:
Note the “results” element at the top of the JSON structure.
In order to resolve this, we need to declare a “schema” in our dataSource parameter for the chart:
Here, we declare the header node = “results” – this is all that is needed to enable Kendo to correctly traverse the JSON model.
A Kendo forum post regarding this issue can be found here:
http://www.telerik.com/forums/kendo-chart-e-slice-is-not-a-function-with-remote-data
Resulting UI
The result of our efforts:
As can be seen, Las Vegas is the place to steer clear of, regarding zombies.
Changing the chart type: Donut chart
With the above framework in place, it’s fairly easy to create new chart types. We simply alter the createChart function to specify a different type:
Result:
(Note that some chart types are suitable for specific types of data – depending on the complexity of the data).
I hope this provided some ideas of what is possible; the concepts should be useful also for other 3rd party UI libraries.
These examples were developed using Web IDE on a HANA Cloud platform, with data pulled from a Gateway system.