Structuring an SAPUI5 application with MVC
After playing with the beta shipment of the UI Development Tookit for HTML5 aka SAPUI5 for a bit over the last week I took away a very positive first impression. The environment was straight forward to setup, the documentation detailed and useful, the code did what the documentation promised as far as I could tell and the resulting web application looks nice and clean and is responsive. That’s already more than what I would generally expect from a beta program so a clear thumbs-up to the SAP product team on these aspects!
On the other side I could have done with better IDE support (new project wizard, code assist, etc.), but understand that’s on it’s way. What I was also missing was a more comprehensive example that shows how the various concepts hang together and where I could get a sense of how to best structure my project. I hope we’ll see that included in the next version of the documentation, but in the meantime here is what worked for me.
Here’s my sample scenario
So let’s get started. The target I set myself was to build a simple event calendar where the panel below the events calendar would show the details of the selected event.
I was mostly interested in the UI aspects so was just going to simulate a data source rather than actually write one.
Setting up the environment
It usually pays of very quickly to have your IDE tightly integrated with the test environment and I found that’s also true for SAPUI5 development, especially since Eclipse wasn’t able to validate the code I wrote on the spot so I had to do lots of testing in the browser. I therefore started with importing the “getting-started-sample.war” file that comes with the beta shipment into Eclipse (Indigo SR1) and stripped it down to just an index.html, but kept the .jar files and the web archive descriptor. Once I got this new project deployed successfully into my local Tomcat 7.0 server and any changes I made to it in Eclipse were automatically synchronised into Tomcat I knew I was ready to go.
Model View Controller
After spotting the MVC support in the SAPUI5 documentation I quickly settled on the following structure to split up the various concerns of the UI into manageable units.
The ‘index.html’ bootstraps the SAPUI5 libraries and includes my main JavaScript application file, which I called ‘app.js’.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Events</title>
<script id="sap-ui-bootstrap" type="text/javascript"
src="resources/sap-ui-core.js"
data-sap-ui-theme="sap_goldreflection"
data-sap-ui-libs="sap.ui.ux3, sap.ui.commons, sap.ui.table">
</script>
<script src="app.js">
</script>
</head>
<body class="sapUiBody">
<div id="uiArea"></div>
</body>
</html>
Inside the body tag you’ll notice a ‘uiArea’ div placeholder which is where the ‘app.js’ script will place the SAPUI5 application shell.
This ‘app.js’ is also where all the different MVC components are bound together.
//construct and configure the app shell with a single worksetitem
var shell = new sap.ui.ux3.Shell("objectivesAppShell", {showSearchTool:false, showInspectorTool:false, showFeederTool:false, showLogoutButton:false});
shell.addWorksetItem(new sap.ui.ux3.NavigationItem({key : "wi_Events", text : "Events"}));
//construct the view
var eventsView = sap.ui.view({ type: sap.ui.core.mvc.ViewType.JSON,
viewName: "mypackage.Events",
controller: sap.ui.controller("mypackage.Events")
});
//load and bind the model
var eventsModel = new sap.ui.model.json.JSONModel();
eventsModel.loadData("Events.json");
eventsView.setModel(eventsModel);
var eventsList = eventsView.byId("eventList");
eventsList.bindRows("events");
//place view in app shell, app shell in uiArea
shell.setContent(eventsView);
shell.placeAt("uiArea");
The “mypackage.Events” view is constructed from a JSON file that by convention needs to be called ‘Events.view.json‘ and lives in ‘/resources/mypackage’.
{
"Type":"sap.ui.core.mvc.JSONView",
"content": [{
"Type":"sap.ui.table.DataTable",
"id":"eventList",
"title":"Events Calendar",
"visibleRowCount":5,
"selectionMode":"Single",
"columns" : [{
"Type":"sap.ui.table.Column",
"label":"Date",
"width":"20%",
"template": {
"Type":"sap.ui.commons.TextField",
"value":"{date}"
}
},
{
"Type":"sap.ui.table.Column",
"label":"Event",
"template": {
"Type":"sap.ui.commons.TextField",
"value":"{title}"
}
},
{
"Type":"sap.ui.table.Column",
"label":"Location",
"width":"20%",
"template": {
"Type":"sap.ui.commons.TextField",
"value":"{location}"
}
}],
"rowSelect":"onRowSelect"
},
{
"Type":"sap.ui.commons.Panel",
"id":"eventDetail",
"title":{
"Type":"sap.ui.commons.Title",
"text":"{title}"
},
"showCollapseIcon":false,
"content":[{
"Type":"sap.ui.commons.TextView",
"text":"{description}"
}]
}]
}
Alternatively this view could have been loaded from an XML file or created programmatically in JavaScript. I personally prefer the declarative approach for view definition since it enforces a clean separation between view creation, data bindings to the model and controller logic. And who knows, maybe we’re even going to get some visual layout tooling to produce this JSON View file more easily.
The “mypackage.Events” controller is a JavaScript file that by convention needs to be called ‘Events.controller.js‘ and also lives in ‘/resources/mypackage’. This is really where the separation between view and controller starts to pay off since it’s now easy to spot and comprehend the actual logic and event handlers of this little application.
sap.ui.controller("mypackage.Events", {
onInit : function() {
this.byId("eventDetail").setVisible(false);
},
onRowSelect : function(event) {
eventDetail = this.byId("eventDetail");
eventDetail.bindContext(event.getParameter("rowContext"));
eventDetail.setVisible(true);
}
});
And finally, here’s the data that I loaded into the model via the ‘Events.json‘ file.
{
"events" : [{
"date":"October 15-19",
"title":"SAP TechEd 2012",
"location":"Las Vegas",
"description":"SAP TechEd is the premier technical conference offering over 1,000 hours on SAP technologies, focused on SAP NetWeaver, analytics, and mobile platforms. Enhance your skills by attending hands-on workshops, demo-driven lectures, and Q&A sessions on the latest developments in analytics, mobile, cloud, database, and in-memory computing. Make valuable connections with peers and distinguished IT professionals from our SAP community."
},
{
"date":"November 13-15",
"title":"SAPPHIRE NOW 2012",
"location":"Madrid",
"description":"Transform your business with essential information and best practices for business executives, lines of business, and IT decision makers, and business managers."
},
{
"date":"November 13-16",
"title":"SAP TechEd 2012",
"location":"Madrid",
"description":"Run smarter with education for IT professionals. Over 500 hours of hands-on workshops and in-depth technical training plus access to all SAPPHIRE NOW content."
},
{
"date":"November 28-30",
"title":"SAP TechEd 2012",
"location":"Bangalore",
"description":"Registration opens this summer. Check back for event details."
},
{
"date":"December 4-5",
"title":"SAP TechEd 2012",
"location":"Shanghai",
"description":"Registration opens this summer. Check back for event details."
}]
}
Assuming that a backend service would produce an identical output it would be trivial to later swap out this dummy data with a live data source. Using dummy data can also be useful in other contexts, e.g. to bridge the time on a project until the actual data source becomes available or if the frontend developer doesn’t have (continuous) access to the backend service.
So what do you think? Is this a structure that could scale to larger SAPUI5 projects? How would you structure your SAPUI5 project?
Thanks for sharing your experiences.
I think the structure looks good and should scale.
Personally I would prefer to use JSView instead of JSONView as it is more flexible in non-trivial examples (as you can code around them).
It would be interesting to see how sapui5 MVC part compares to the very popular MVC framework Backbone.js http://documentcloud.github.com/backbone/
I get the impression that most javascript developers nowdays know and like Backbone.js.
The main question is really; why should I use sapui5 MVC paradigm, instead of Backbone.js?
Just stumbled over the SAPUI5 / MVC discussion on Google+ between you and John from two weeks ago on this very same topic. It seems we've all been running into the same question so that should make a good case for SAP to enhance the SAPUI5 documentation with some more comprehensive examples. In the meantime I am all for sharing some more sample code here on SCN. An example where SAPUI5 runs integrated with Backbone.js would indeed be a good one!
I think this is much better forum for discussions like this 🙂
Are there any examples/experiments on integrating SAPUI5 with Backbone so far?
Thanks for sharing,
The beta version is great, but I keep asking myself similar questions to you; how best to structure my projects and what would be the best way to manage and control code on larger developments which require multiple developers?
Hopefully in future releases we get more comprehensive examples, tighter integration to the IDE and documented best practices.
I also agree with Dagfin, and would go so far as to say if sapui5 is to be widely adopted by developers the MVC implementation is make or break, it needs to be compelling when compared to other popular frameworks.
Lastly I thought I would share something I just discovered. I got your example up and running in minutes, very nice by the way. I thought I would see if i could get it working on a local server where the sapui5 library wasn't installed, thinking both local development and CDN scenarios.
I followed the MVC documentation and added to the following line to app.js
jQuery.sap.registerModulePath("mypackage", "http://localhost/mypackage");
Replaced the resource path of the sapui5 library in index.html and deployed on the iis on my laptop (after adding a mimemap for *.json).
And it works well in IE but not Google Chrome, something that seems to happen to a lot.
Update: just tried without luck on FF and Safari also, it appears it maybe a CORS issue which makes sense.
Cheers
JSP
Hi,
I am very curious how to get the json data (i.e. Events.json)?
Could you please give some details how to get json data from SAP server / gateway, etc.?
I am interested using json data for jQTouch and jqMobi for iPhone/iPad mobile development.
Thanks.
Noli
Hi Noli,
The blog SAPUI5 says "Hello OData" to NetWeaver Gateway shows how to bind a Data Table to a NW Gateway OData service.
Steffen
I am new to SAP UI5, i am trying to implement MVC pattern using XMl View
<mvc:View
controllerName="view.Config"
xmlns="sap.m"
xmlns:core="sap.ui.core"
xmlns:mvc="sap.ui.core.mvc"
xmlns:h="http://www.w3.org/1999/xhtml">
<Page
title="Offline OData Demo"
icon="{img>/icon/ui5}">
<content>
<CheckBox
class="configCheckBox"
text="Trace On"
enabled="true"
checked="true"
select="buttonTraceOnOn"
/>
</content>
</Page>
</mvc:View>
java script file
buttonTraceOnOn:function(evt)
{
alert(evt+"Trace On");
},
I am getting the alert, but not able to retrieve if the Checkbox value is checked or not?
Any help is appreciated 🙂
Regards,
Manjunath.