The origin of becoming a fundamental enabler for Fiori

30 Days of UI5 - Day 30 by Sam Yen, Chief Design Officer, SAP

Not too long ago, before Fiori was Fiori, SAP had tried several times to refresh the user experience.  I’m aware of over 20 different UI technologies that we have used since the release of R/3.  As mobility was sweeping into the enterprise, SAP adopted a native mobile development approach.  At the time, many believed that this was an opportunity to create modern experiences with modern UI technologies (primarily iOS at the time) and development environments to refresh the SAP User Experience.

The first mobile apps showed promise, but as we started to roll out more and more, quality suffered.  The experience of some of the native apps were good, some bad.  We noticed a lot of creativity in building different ways to do the same things.  This came to a head when some of our large customers evaluated SAP’s mobile app portfolio as a whole and were not happy about this experience.

Design consistency was one thing.  Also, we considered the full lifecycle of these apps. Currently, there are over a thousand permutations of android software and hardware configurations in the market today.  Even Apple now has several versions of screen sizes and resolutions to support from tablets, phones, and now watches.  Cost of development, support, and ownership pointed to a modern, but scalable approach.  We made a decision to go with a responsive HTML5 approach.

Luckily, SAP had been developing HTML5 controls at that time.  As with other HTML5 libraries at the time, UI5 was separated between the desktop controls and the mobile controls.  We took the decision to combine the best of what we had and create a responsive UI5 control set for Fiori.

I may have understated the part about our customers being unhappy about the user experience.  It was escalated to the highest levels and we were under tremendous pressure to demonstrate to customers that this new concept would fly – quickly.  We had 6 days, 144 hours to be exact, to demonstrate to internal stakeholders the both the desirability and feasibility of our approach.  I’ll never forget Stefan Beck and the UI5 team walking down the halls of Walldorf to our war room saying that, “the UI5 team will support you.”

section1-1That was the beginning.  Since then UI5 and the team behind the technology have expanded much beyond a mere set of controls.  The team has helped to develop a programming model that is open and designed to scale for the enterprise.  It is part of growing set of tools to make UI development both efficient and scalable both for SAP and the industry.

Looking forward we’ll start to augment our responsive design approach to also leverage native, on-device capabilities.  Analytics will become more of an area of focus.  I have said many times that I feel my role as Chief Design Officer is to change the perception of SAP’s user experience. Fiori has done much for SAP to start that perception change, but I am acutely aware that we are only just beginning on our journey.  I also feel that SAP’s journey is also the same journey that the entire IT industry will need to follow to bring great experiences to our users.

Revisiting the XML Model

Screen Shot 2015-08-01 at 11.56.5030 Days of UI5 - Day 29 by DJ Adams

It’s been more than a couple of years since I first had a look at XML data in the context of UI5. In my “Re-presenting my site with SAPUI5” video I used an XML Model to load the XML feed of my weblog into a UI5 app (gosh, JavaScript views!).

The XML Model mechanism proved very useful this week on a project, and I thought I’d re-examine some of its features. Everyone knows about the JSON and OData Model mechanisms; at least in my UI5 conversations, I don’t hear folks talk about the XML Model much. So I thought I’d give it some love here.

The API reference documentation for the XML Model is a little dry. As Frank Zappa once said, “The computer can’t tell you the emotional story. It can give you the exact mathematical design, but what’s missing is the eyebrows“. We need to look elsewhere for the emotional story, for the eyebrows; and I think a nice place might be the QUnit tests for the XML Model.

Learning from the QUnit sources

Let’s have a look at the source, and see what we can learn. There are actually a couple of QUnit test files; we’ll have a look at just one of them – XMLModel.qunit.html. We’ll just examine the setup and a couple of tests to see what we can find – what we can expect to be able to do with an XML Model. You can explore the rest of the QUnit test files on your own.

At the start of XMLModel.qunit.html, a couple of XML Models are instantiated with some test data as follows:

	var testdata = "<teamMembers>" +
						"<member firstName=\"Andreas\" lastName=\"Klark\"></member>" +
						"<member firstName=\"Peter\" lastName=\"Miller\"></member>" +
						"<member firstName=\"Gina\" lastName=\"Rush\"></member>" +
						"<member firstName=\"Steave\" lastName=\"Ander\"></member>" +
						"<member firstName=\"Michael\" lastName=\"Spring\"></member>" +
						"<member firstName=\"Marc\" lastName=\"Green\"></member>" +
						"<member firstName=\"Frank\" lastName=\"Wallace\"></member>" +
					"</teamMembers>";
	var testdataChild = "<pets>" +
	  		            "<pet type=\"ape\" age=\"1\"></pet>" +
	  		          	"<pet type=\"bird\" age=\"2\"></pet>" +
	  		        	"<pet type=\"cat\" age=\"3\"></pet>" +
	  		      		"<pet type=\"fish\" age=\"4\"></pet>" +
	  		    		"<pet type=\"dog\" age=\"5\"></pet>" +
	  		    	"</pets>";

setXML and setData

The XML data is added to the XML Models with the setXML function:

	var oModel = new sap.ui.model.xml.XMLModel();
	oModel.setXML(testdata);
	sap.ui.getCore().setModel(oModel);

	var oModelChild = new sap.ui.model.xml.XMLModel();
	oModelChild.setXML(testdataChild);

This is different to the setData function, which is also present on the JSON Model, with an equivalent semantic. Here in the XML Model, the setData function would be expecting an XML encoded data object, not a literal string containing XML.

As an example, if we have a variable containing some XML string like this:

xmlstring = "<root><name>DJ</name></root>"

then we could either set it on an XML Model with setXML, like this:

m = new sap.ui.model.xml.XMLModel()
=> sap.ui.d…e.C.e…d.constructor {mEventRegistry: Object, mMessages: Object, id: "id-1438428838337-6", oData: Object, bDestroyed: false…}
m.setXML(xmlstring)
=> undefined
m.getProperty("/name")
=> "DJ"

or with setData, creating an XML encoded data object, like this:

m = new sap.ui.model.xml.XMLModel()
=> sap.ui.d…e.C.e…d.constructor {mEventRegistry: Object, mMessages: Object, id: "id-1438428927599-7", oData: Object, bDestroyed: false…}
m.setData(new DOMParser().parseFromString(xmlstring, "text/xml"))
=> undefined
m.getProperty("/name")
=> "DJ"

A couple of tests

Then we’re off on the tests. There are a couple of tests to check getProperty, the first using a relative context binding:

	test("test model getProperty with context", function(){
		var oContext = oModel.createBindingContext("/member/6");
		var value = oModel.getProperty("@lastName", oContext); // relative path when using context
		equal(value, "Wallace", "model value");
	});


	test("test model getProperty", function(){
		var value = oModel.getProperty("/member/6/@lastName");
		equal(value, "Wallace", "model value");
	});

What we can see here already is that we can access XML attribute values (“lastName” in this case) with the XPath @ accessor. As an aside, the use of the optional second oContext parameter in the getProperty call is something one doesn’t see very much, but is extremely useful.

Element content retrieval

The rest of the file contain a load of other tests, all useful reading material, from the rare-to-see use of the unbindProperty function to aggregation bindings that are comfortable to use.

One thing that we have to wait until test 15 to see is the use of element content:

	test("test XMLModel XML constructor", function(){

		var testModel = new sap.ui.model.xml.XMLModel(

		);
		testModel.setXML("<root>" +
				"<foo>The quick brown fox jumps over the lazy dog.</foo>" +
				"<bar>ABCDEFG</bar>" +
				"<baz>52</baz>" +
			"</root>");
		equal(testModel.getProperty("/foo"), "The quick brown fox jumps over the lazy dog.");
		equal(testModel.getProperty("/bar"), "ABCDEFG");
		equal(testModel.getProperty("/baz"), 52);

	});

Until now we’ve only seen examples of XML where the data is stored in attributes. What about the more classic case of text nodes, like this example XML here?

Well, as we can see, a simple call to getProperty will do what we want. If we’re XPath inclined, we could even add the text() specification like this:

testModel.getProperty("/bar/text()")
=> "ABCDEFG"

and still get what we expect.

Ending where we started

And of course, to round things off, we can always get back to an XML encoded data object with getObject, like this:

testModel.getObject("/bar")
=> <bar>ABCDEFG</bar>

(that result is indeed an object), in a similar way to how we retrieve the whole object from the model:

testModel.getData()
=> #document
   <root>
    <foo>The quick brown fox jumps over the lazy dog.</foo>
    <bar>ABCDEFG</bar>
    <baz>52</baz>
  </root>

The XML Model is a powerful ally, and the QUnit tests are a rich source of information about it. Spend a coffee break looking through the sources, you won’t be disappointed!

UI5 Version Info

Screen Shot 2015-07-31 at 13.04.2230 Days of UI5 - Day 28 by DJ Adams

Yesterday Peter Müßig from the UI5 team at SAP in Walldorf announced the multi-version capability for SAPUI5.

He also documented the details in a post on the SAP Community Network here: “Multi-Version availability of SAPUI5“. Shortly after, the announcement was also made that this would also be available for OpenUI5.

This is great news, and something that we’ve been waiting for now for a while. It makes perfect sense, and the ability to select a particular runtime version via a part of the bootstrap URL’s path info is very nice. It’s something I do locally on my workstation anyway, and I also have a ‘latest’ symbolic link that I ensure points to the latest copy of the runtime or SDK that I have locally.

Along with the announcement came a link to a simple SAPUI5 Version Overview page, built in UI5. It looks like this:

Screen Shot 2015-07-31 at 13.11.42And if you look under the covers, you’ll see a single-file app, with a lot of custom CSS, some JavaScript view stuff going on, and the retrieval of a couple of JSON resources containing the version overview info and the data from the neo-app.json file that is present in the HCP platform and which describes routes to destinations, which include the SAPUI5 runtime services, now available at different paths for different versions.

You’ll also see some complex manipulation and merging of those two datasets, and the mix of UI5 controls with raw HTML header elements.

Screen Shot 2015-07-31 at 13.22.44The result is an app that looks OK on the desktop but doesn’t look that well on a smartphone, as you can see on the right.

So I spent some time on the train down from Manchester to London early this morning to see what I could do.

I wanted to address a couple of things:

  • have the smartphone as the target device, rebuilding the UI with an App control
  • improve the binding, to a single data collection

The UI part was straightforward. I used my MVC technique (see MVC – Model View Controller, Minimum Viable Code from earlier in this series) to define a new View, declaratively in XML. I used an App control with a couple of Pages, and a simple controller for the view which handled all the view lifecycle and user-generated events, as well as being the container for the formatter functions.

I also used some of my favourite JavaScript functions to bind together the disparate data into a nice cohesive single array of maps. I left the original data manipulation as it was, and then grabbed what it produced to make my array. I could then bind the List in UI to this single array, and then confer the right binding context to the second Page for a selected item from the array.

I’ve created a small Github repo ui5versioninfo with the files. It contains a local snapshot of the two source JSON files (neo-app.json and versionoverview.json), the original versionoverview.html that produces the UI we saw earlier, and a new file, called new.html, which is my quick attempt addressing those things above.

Here’s what the result looks like:

versioninfo

I’ve tried to use some UI5 design and control best practices, while defining the UI in XML. I’ve added some functional programming style data merging to take place after the original manipulation, and a small controller with the requisite functions for event handling and formatting.

I took the screencast of the “finished” attempt on the tube from London Euston to Chiswick this morning, so it really was a rush job. But I think that it’s worth thinking about how we can improve this useful resource. How would you improve it?

 

A non-techie PM’s view of UI5

branches30 Days of UI5 – Day 27 by Jon Gregory

I’m mid-flight in my first UI5/Gateway project, working with a great team of developers who have all contributed to this 30 Days of UI5 series. As a non-techie Project Manager embarking on mobile development for the first time, I thought I’d share some of my experiences and tips.

This isn’t regular SAP configuration – this is mobile development.

My experience of SAP to date has been in software modules – EPM, BW, CRM, for example. It’s easy to think of a UI5/Gateway project in the same way because they’re SAP products, but putting the name to one side, the difference between enterprise software and mobile development is huge.

This is obvious to those familiar with mobile development, but not so obvious to those new to this area. Prior to embarking on any UI5 project, get hold of case studies, project plans, artefacts, lessons learned and people that have delivered UI5 applications to get an understanding of how to set your project up for success. If you’re experience is largely in enterprise software projects, this is going to be very different :-).

Nail your branch & review strategy early on

At the beginning of the project, work with your team to develop a branch & review strategy. Agree a process for matching short-lived feature branches to tasks, for reviewing code prior to any merging, and also ensure that development branches are tidy and up to date – that is, delete any old branches, or branches that are no longer needed.

A friend told me a story of a time when he was working in a fast moving and experienced frontend/toolkit development team. He’d had a scattering of branches lying around his local repo, and a Ukranian colleague, in a thick accent, speaking German, reprimanded him gently but firmly: “What are all these branches doing clogging up your workspace and your brain? Get rid of them!”.

Allow enough time for planning – agile doesn’t excuse poor process

I found it’s easy to run in to development with a bunch of user stories and little else. Although UI5 lends itself to agile development, there still needs to be adequate time allocated to planning sprints, and also fundamental architecture design, not only for the UI itself, but for the data design and integration. Factor this in to your plans from the very beginning and don’t budge – if anything should give as a result of time, cost or scope constraints, it mustn’t be the preparation that goes in to making sprints a success.

Embrace it

Working with UI5, I’ve discovered methods of project delivery that are entirely different from the standard Waterfall/ASAP approach so often adopted in enterprise software projects. I’ve also found it hugely rewarding to see an intuitive, easy to use application come to life and, more importantly, so has our customer (case study is in progress – more on that soon).

So in summary, my advice is:

  • Forget about normal SAP – walk in with an open mind
  • Set out development processes with your team from day one
  • Plan, plan, plan
  • Enjoy it!

I’d be really interested to hear about other experiences of managing or coordinating UI5/Gateway projects, and listen to any advice you may have.

UI5 – looking back and forward

Screen Shot 2015-07-29 at 07.33.3030 Days of UI5 - Day 26 by DJ Adams

It was in the spring of 2012 when I wrote this piece about the new kid on the block, SAPUI5:

SAPUI5 – The Future direction of SAP UI Development?

The fledgling toolkit had been released at version 1.2 earlier that year, and while it had clearly been in gestation for a while inside SAP, it was still new and raw enough to make folks wonder what it was all about. More than the newness or the rawness was how it was different, how it changed the rules. And what made it even more interesting was the fact that while SAP had changed a lot of rules since the 80s, this time, it was SAP embracing common practices and growing standards outside its own development ecosphere. And that was a good thing.

So SAPUI5 was not just a toolkit, it was more than that. It was arguably the poster child for how SAP was changing, changing to embrace, adopt and build upon open standards and protocols.

Of course, that had been happening for a while, most notably, at least in my opinion, by the introduction of the Internet Communication Manager (and corresponding user-space Internet Communication Framework) to the R/3 architecture, allowing SAP systems to speak HTTP natively. And there was OData, which SAP adopted as a REST-informed protocol and format for the next generation of business integration. It had been a long time coming; the journey from service-orientation to resource-orientation starting from the mid 2000’s — with posts like this: “Forget SOAP – Build Real Web Services with the ICF” :-) — was long and arduous.

So it was met by some with trepidation, wonder, cynicism even. But the rise and rise of UI5’s success has been undeniable. Success not only in becoming the engine powering the first SAP Fiori UX revolution, but also in the move towards a more open and outward facing development approaches.

The UI5 teams of designers and developers themselves, in Walldorf and around the world, have open software and standards in their DNA. UI5 itself has been open sourced. The development standards and processes are, out of necessity, different. And we can see that first hand. Just look at the home of UI5 on the web – at https://github.com/SAP/openui5. Github!

Screen Shot 2015-07-29 at 07.18.18

The development process is there for us to see, warts and all. The smallest changes are being done, in public. Look at the one authored 11 hours ago in this screenshot. It’s a simple improvement for variable declaration in the code for the Message Popover control in the sap.m library. It doesn’t matter what it is, what matters is that it’s open. For us all to see, scrutinise, and most importantly, learn from.

UI5 powers SAP Fiori, the services of their cloud offerings (for example in the form of the Web IDE, written in UI5) and of course the S/4HANA business suite. It’s destined to become a part of the future normal. It’s a toolkit with a strong pedigree, a toolkit that is not perfect (I can’t think of any software that is) but a toolkit with passionate folks behind it. It’s gaining some adoption outside of the SAP ecosphere too, and in some cases is almost becoming part of the furniture – not the focus of energy, but the enabler of solutions. It Just Works(tm) and gets out of the way. That for me is a sign of growing maturity.

The experimental Client operation mode

Screen Shot 2015-07-28 at 12.53.4530 Days of UI5 - Day 25 by DJ Adams

A few months ago a preview release of 1.28 was made available. In the blog post that accompanied it, a number of the new features were introduced. Without much fanfare, certainly without any cool looking screenshots, the experimental “Client” operation mode was announced for the OData Model mechanism.

OData Model – Server-side

The OData Model is special, in that it is classified as a server-side model, unlike its client-side siblings such as the JSON Model or the XML Model (or the Resource Model, for that matter). This means that the data “home” is seen as the server, rather than the client (the browser). Consequently, any operations on that data, even read-only operations such as sorting and filtering, take place on the server. That means extra network calls. There are truly marvellous advantages also, which the margin [of this post] is too narrow to contain. 

There are circumstances, even when dealing with entity sets in OData services, where sorting and filtering could and should take place on the client, rather than on the server. To this end, 1.28 brought an initial experimental feature to the OData Model mechanism – the OData Operation Mode.

Operation Mode

The Operation Mode joins a small but important set of modes relating to the OData Model mechanism. By default, the Operation Mode is “Server”. But it can be set to “Client”, which causes all data to be loaded from the server and for subsequent sorting and filtering operations to be performed in the client, without further network calls. As the blog post mentions, this only really makes sense as long as there isn’t a ton of data.

Note that the Operation Mode is related to the OData Model mechanism instantiation in that it is the default for that model instance. You actually specify the mode for a binding, as shown in the code snippet in the blog post:

oTable.bindRows({
   path: "/Product_Sales_for_1997",
   parameters: {
      operationMode: sap.ui.model.odata.OperationMode.Client
   }
});

Experiment!

This experimental feature was crying out for … well, experimentation. So I threw together an MVC (model view controller, minimum viable code) based app to test it out. Here’s the result:

clientoperationmode

Here we have a test app with a List, where the items aggregation is bound to the Categories entity set in the public Northwind OData service at http://services.odata.org/V2/Northwind/Northwind.svc/.

Note that the Operation Mode is only available on the v2 version of the OData Model mechanism, so that’s what I’m using here.

Initially the binding to the List’s items aggregation is with the (default) value of “Server” for the Operation Mode. You can see the network calls that are made to ask the OData service to return the entities in a specific order (with the $orderby OData parameter) each time I hit the sort button, which is toggling between ascending and descending sorting of the category names.

But then, in the console, I grab the List, and re-bind the items aggregation, to the same path (“/Categories”) but in “Client” Operation Mode. The result is that a new call is made to fetch the entities to satisfy that (new) binding, but further sorts are done entirely on the client – there are no more network calls made.

I’d call that experiment a success, and I’m looking forward to developments in this area. Nice work, UI5 team!

An introduction to sap.ui.define

Screen Shot 2015-07-27 at 11.04.0230 Days of UI5 - Day 24 by DJ Adams

If you’ve followed this series you’ll have come across the OpenUI5 Walkthrough, a “a great multi-step walkthrough of many of the features and practices of UI5 development”.

In Step 5 of the walkthrough, on “Controllers”, we’re introduced to something that looks unfamiliar. Especially to those who have written large numbers of controllers thus far, for example. The way the XML View’s Controller is defined is … different. Step 5 doesn’t say much specifically about how this works, but Step 6, on “Modules”, does.

This is what the Controller source code looks like:

Screen Shot 2015-07-27 at 10.13.53

So what’s happening here?

Well, what’s happening is that we’re seeing the beginning of a migration to an Asynchronous Module Definition (AMD) style mechanism. And the principle vehicle for this is a new function sap.ui.define, which was introduced to the world in 1.28 (1.27 internally).

There’s already some API documentation for this experimental new way to define modules that you can read in the API reference guide for sap.ui.define itself. There you’ll see how there’s a transition planned away from synchronous, and towards asynchronous loading. You’ll see for example that the optional fourth parameter “bExport” of sap.ui.define is there to support that transition.

While there’s plenty to read there, let’s just take a quick look at what it means for those like us at the UI5 coalface. We’ll take the code in the screenshot above as an example:

Instead of calling something like this …

sap.ui.core.mvc.Controller.extend("your.name.here", {
  // your controller logic here
});

… we can use the new more generic sap.ui.define to first of all declare dependencies and then define the factory function that becomes the controller, in this case. Let’s take a look at the code and examine it line by line:

Screen Shot 2015-07-27 at 10.42.52

1-14: The call to sap.ui.define extends across all the lines here; and we can see that out of the four total possible parameters described in the API reference, only two are used: the optional list of dependencies (represented here by the array) and the factory function that has a single statement returning an extended controller.

2-3: These are the dependencies. We’re defining a Controller, so we’ll want to extend UI5’s core controller (in the same way that we often do, such as in the example earlier). For that, we have a dependency on sap.ui.core.mvc.Controller. We’re also using the Message Toast’s “show” function, so we declare a dependency on sap.m.MessageToast. Note that the dependencies are expressed as resource paths (with the .js suffix omitted of course).

4: The second parameter passed in the call to sap.ui.define is the factory, and we can see the function definition start here. Note that each dependency reference is given to this factory function, in the same order that they’re declared in the dependency list. By convention, the most significant part of the resource path name is used for the parameter name (for example “Controller” for sap.ui.more.mvc.Controller).

5: The call to “use strict” is not specifically a feature of the new module definition syntax, but it is significant in that there is growing focus on JavaScript syntax correctness and linting. For more on this, see another post in this series: “UI5 and Coding Standards“.

7-12: The rest of the source code looks fairly familiar. There’s one exception though, and it’s a result of the dependency mechanism described earlier. The function has “Controller” and “MessageToast” available to it, and so we can and should use these to refer to the sap.ui.core.mvc.Controller and sap.m.MessageToast resources throughout. This is nice, and makes for slightly neater code too.

It’s early days for the new define mechanism, and there’s clearly a journey ahead for those in the core UI5 team looking after fundamental module and dependency loading and management mechanisms. But even at this early stage, it’s worth paying attention to the direction UI5 is going in this regard, and start to experiment. I know I will be!

Taming the Resource Model Files

30 Days of UI5 – Day 23 by Nathan Adams

UI5’s support for multiple-languages, out of the box (see the post “Multi-language support out of the box – UI5’s pedigree” in this series) is impressive and easy to use. Creating a message resource bundle in your Component.js file is straightforward, especially if picking up the user’s language preferences in the browser.

What can be less straightforward though is organising these files into something manageable, for plenty of projects, your i18n file might be on the small side, but it’s pretty easy to build up a large file. An application I’m currently working on, which perhaps has only 50% of its views defined, already has just 100 definitions in the i18n file. (A quick look at the Fiori My Travel Expenses App v2 shows there are around 1000 lines, and about 500 definitions in the resource file and whilst reasonably well documented with comments – you may well be hunting for usage of a text).

#XBUT,20: Button that distributes (shares) the total amount evenly between all attendees
DISTRIBUTE_EVENLY=Distribute Amounts Evenly

#XBUT,20: add internal attendee button
ADD_INTERNAL_ATTENDEE=Add Internal Attendee

#XBUT,20: add external attendee button
ADD_EXTERNAL_ATTENDEE=Add External Attendee

#XFLD,20: FirstName – LastName in the right order, e.g. EN: Smith, John
ATTENDEE_FULLNAME_ARTIFACT={1}, {0}

#XTIT: title of Add Internal Attendees select dialog
INTERNAL_ATTENDEES_TIT=Add Internal Attendees

#XTIT: title of Add External Attendees dialog
EXTERNAL_ATTENDEES_TIT=Add External Attendees

Example of a Fiori Resource Model file from ‘My Travel Expenses’

Before we dive into the structure of the key value pairs of the file though, it’s worth thinking about if one file for all your texts makes sense. In the majority of cases, you really wouldn’t want to add further complexity by adding more files. in my experience though, there are some cases where creating additional resource files may be useful.

  • You may have texts which are more prone to change, perhaps email / telephone contact details in messages; putting these into a separate file might make sense to de-risk the process of updating them when they need to change
  • Common elements across a suite of applications
  • Master data texts, if you have a lot of these, then consider separate files for them
  • You may have texts, or elements of texts which don’t need translation, and you want to keep consistent across all languages (that email example above, you don’t want to update that in multiple language files every time)
  • Lastly just like code – if it’s too long, break it up. Large app with 100’s if not 1000’s of terms? Split it up, maybe by view, or group of views.

As we move on into the structure of these files, it might not seem to be important (you can always search for a term in your chosen IDE after all), but like all good coding practices, structure can be immensely helpful in the following regards

  • Identifying gaps in language files becomes easier – so you don’t discover in the first round of translation that you had some texts hardcoded into your XML views
  • Making changes to texts, when a change is requested becomes a lot easier
  • When sending out for translation, identifying which text is which becomes easier
  • Because the file can be more easily understood, then it becomes an easier artefact to distribute, potentially removing the need for conversion back and forth between spreadsheets

How you choose to organise the language file is a matter of preference, however in my experience there are two key things I like to highlight and organise in the language file:

  • Common terms
  • Terms organised by View or Fragment / Control / Property

I’ll define all the common terms at the beginning of my language file. My preference for all my keys, is to use a dot notation to specify them (as it lines up nicely with identification of components). So here’s an example

#Common Terms
common.thing=Foo
common.items=Items
common.add=Add

Thing is though, common terms feel like something I should have in my application; you want to make sure that when you call a thing, Foo it’s always a Foo and when it’s requested to change to Bar I can change the common term, and my job is done. In practice though, this never really works. Why? Well I might be able to define those common terms, but in the majority of cases I always need to fit them into a longer text, such as Create a Foo or Delete Foos.

OK so maybe I can define some common texts, and do some clever pre-processing with Grunt to expand placeholders in my text, or do the same when I load the resource file

#Specifc Terms (pre-process)
master.things.addThing=Add {common.thing}
master.things.deleteThings=Delete {common.thing}s

#Specific Terms (post-process)
master.things.addThing=Add Foo
master.things.deleteThings=Delete Foos

Nice? Well not really, it’s not a great practice to make longer texts out of shorter texts. Consider the need to correctly handle plurals or other modifications you might require. Let’s say we can have Foos but it’s not Bars but Baren then my nice easy change above isn’t going to work. Then other languages might not have the same syntactic structures, and I could finish up chasing my tail trying to get it right across all languages, or finishing up like those pre-recorded train announcements made up of single recorded chunks – they work, but just sound awful.

There is one valid place for common terms, and you might therefore still want to define them in your main i18n file (or even a separate one you don’t load). That’s as a glossary to help those maintaining the file. Adding common.thing=Foo to the head of the file, even if never used will help those coming along after to understand how things are referred to. It’s a good UX practice, and fundamental to building a consistent experience.

So most of my definitions though, will be very specific to a view or fragment, and therefore, I like to identify these, in this manner, with the application as an implied root. If I’m developing a Split App, which has for example the following views

  • Tasks (Master)
  • Services (Master)
  • Rounds (Detail)
  • Details (Fragment used in Rounds)

then I’ll structure my language file, very specifically to reference the view, the control(s) in the view, and where appropriate the property. Which might result in something like.

#Master views
#Tasks
master.tasks.title=Maintenance Tasks
#Services
master.services.title=Active Services
master.services.toolbar.button.add=Add Service
master.services.toolbar.button.delete=Delete Services
#Detail Views
#Rounds
detail.rounds.title=Round Definition
detail.rounds.tabBar.tab.details=Details
detail.rounds.tabBar.tab.vehicles=Vehicles
#Rounds / Vehicles fragment
detail.rounds.fragment.vehicles.column.title.service=Service
detail.rounds.fragment.vehicles.column.title.capacity=Capacity

Admittedly this is quite a verbose approach, and it requires a little discipline to use, but the advantages are plain to see – I immediately get a sense of where a text might appear in the user interface, I also can get a sense of if anything is missing (for example I’d expect every view to have a {view}.title attribute.

By taking a structured approach to the language file, it also makes it easier to set up controls with bindings to the language file, as there is no need to try and think of a name. It goes without saying that you should be building your xml views with bindings for texts from the very start of development – no one wants to go back and to add them all in at a later date (if you do, that’s precious velocity you’re wasting).

Who thought such a straightforward flat structured concept could require so many considerations?

Merging lists with UI5

30 Days of UI5 – Day 22 by Chris Choy

Whilst recently developing a custom UI5 app with an SAP PI backend, I came across some useful mechanisms. My aim was to merge 2 sets of data from 2 service calls into an Object List Item.  Having already bound one set of data my XML View my initial thought was to perhaps use a formatter and pass in 2 arrays of objects and manipulate the data within the Formatter.js file. As you probably guessed, this simply didn’t work, I should mention that both service calls return data in a JSON format rather than standard OData. My next approach was to manipulate the 2 arrays in the View’s controller and merge them both into a new sorted array assigning it to the Component’s Model. One of the benefits of doing this is that you can define your own attribute names and data which is then globally accessible within the app.

Using the code below you can specify a path to set your new data:

this.oModel.setProperty("/newPath", mergedArray);

One other related issue was the searching of specific object attributes within an array of objects. The context of this search was to allow a user to select an item from an Object List Item and load additional data in a new View. Having already passed the relevant parameters within my Router it was jQuery to the rescue. The jQuery.grep function allows you to perform wildcard search on an array of attributes without the need to manually loop through each element. By passing an array as an argument a test against a defined index is performed returning all the entries that satisfy the function as a new array.

var aResult = $.grep(dataArray, function (e) {
  return e.attributeName.indexOf(("searchAttribute",) == 0;
});

One last interesting mechanism used was the storing of hidden Custom Data objects within an XML View. Using the following:

xmlns:app="http://schemas.sap.com/sapui5/extension/sap.ui.core.CustomData/1"
<ObjectListItem
  title=”List”
  app:key="{hiddenKey}" />

you can access the Custom Data object using the data() method within the Controller of your View.

For additional information checkout the following links jQuery.grep and CustomData objects.

 

Spreading the UI5 Message

Michael Graf at OSCON (photo by Janina Blaesius)

30 Days of UI5 – Day 21 by DJ Adams

If you’re reading this post, or this whole series, it’s very likely that you already know something about UI5. Whether that’s coming from the SAP enterprise angle with the SAPUI5 flavour, or from the Open Source angle with the OpenUI5 flavour. But there are plenty of other souls out there that are still missing the UI5 salvation :-). And so I thought I’d briefly review the sorts of activities that have been happening over the last couple of years as far as evangelism, education, and advocacy are concerned.

This is very timely, as this year’s OSCON has just finished in Portland, and a couple of UI5 team members Janina Blaesius and Michael Graf were there with a session on OpenUI5 : “No more web app headaches“. Good work folks! OSCON is O’Reilly’s Open Source Convention, a venerable conference that I’ve been lucky enough to attend and speak at on and off since 2001. Last year, I co-presented a tutorial session on OpenUI5 at OSCON with Andreas Kunz and Frederic Berg – two more heroes from the same UI5 team as Janina and Michael.

Not only that, but the great news is that at the EU version of OSCON, taking place in Amsterdam in October this year, there’s another session “Don’t Disconnect Me! The challenges of building offline-enabled web apps” by another mighty UI5 team combo of Christiane Kurz and Matthias Oßwald. Awesome!

And even if you omit the usual suspect conferences such as SAP TechEd, there’s plenty more, far too much to list in this single post. But here’s a quick selection:

FOSDEM : OpenUI5 at FOSDEM 2015

Mastering SAP : Speaking at Mastering SAP Technologies

SAP Arch & Dev : Speaking at the SAP Architect & Developer Summit

Fluent : OpenUI5 at Fluent Conference 2015

JSNext : OpenUI5 at JSNext Bulgaria

DevoxxUK : DevoxxUK – One does like to code!

SAP Inside Track : SAP Inside Track ManchesterSAP Inside Track Sheffield – UK

SAP CodeJam : SAP CodeJam Liverpool – OpenUI5

Bacon : OpenUI5 at BACON Conference

In September there’s another SAP Inside Track in Sheffield, where there will be talks on UI5 of course (well, I’m going! ;-) and a whole second day dedicated to learning and hacking with UI5.

I’m sure I’ve missed out some UI5 activities, so please let me know of others that have happened. And perhaps more importantly, let me know of any that are coming up, especially any that you’re planning, and I can add them here. Share & enjoy!