IBM i Modernization - The User Interface
(Part 6)
This piece continues my coverage of browsers and client-side technologies. I'm looking forward to moving on to the IBM i side of the interface. But it may help to cover things that may be less familiar to IBM i developers, first. The material is intended to be progressive. A caveat is that this material may be somewhat advanced for some. I'll address it step by step.
Let's Begin
One aspect that carries over from the green-screen paradigm to browsers is the idea of merging "layout" with "data" to create your stunning masterpiece (that which appears on the screen). I hope you enjoyed the hyperbole.
The layout in this context is an HTML template (as opposed to a display file), that has been enhanced by attaching references to a style sheet. The data, presumably comes from an IBM i database, or some other data source that may be accessible from an IBM i program.
Under the display-file paradigm, and also under the traditional web-application paradigm, the merging of layout and data occurs on the server. That's still a valid paradigm. But it's also possible to perform the merge in the browser, and thus save some network bandwidth along with reducing server CPU cycles.
The "phones" application, which is embedded in the following HTML <iframe> element shows an example of merging HTML templates with JSON data objects - where the merge occurs in the browser rather than on the server.
Phones Application
Please navigate within the application by clicking on hyperlinks, images, and using the browser's back and next buttons. The UI consists of two (2) main panels. A phone list. And phone details.
How Does it Work?
Let's first have a look at the initial HTML page. Looks pretty simple, eh?
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" device="mobile">
<title>Phones</title>
<link href="phones.css" rel="stylesheet">
<script src="../apps/common/scripts/ht_merge.js" defer></script>
</head>
<body>
<h1>Phones</h1>
<a name="phones" ht-container="phones" ht-href="phones.html" ht-jref="phones.json" ht-repeat ht-class="fade-in" ht-cache></a>
<a name="phone" ht-container="phone" ht-href="phone.html" ht-after="after_phone()" ht-class="fade-in" ht-cache></a>
</body>
<script src="phonelist.js"></script>
</html>
Although a relatively small block of code, the HTML may look a bit cryptic. I'll break it down and explain it.
<meta name="viewport" content="width=device-width, initial-scale=1" device="mobile">
The <meta> tag causes the page to scale nicely on mobile devices. However, that behavior is somewhat thwarted by my having embedded the page in an <iframe> for this article. It works great when the application URL is evoked from a browser's address bar.
<title>Phones</title>
The <title> tag makes the word "Phones" appear in the browser's window bar or tab. However, that behavior is also thwarted by my having placed the page in an <iframe>.
<link href="phones.css" rel="stylesheet">
This application has some new styling that I was playing with, including some fade-in animation, that is referenced in a style sheet (phones.css).
<script src="../apps/common/scripts/ht_merge.js" defer></script>
ht_merge.js is a relatively small JavaScript utility that merges HTML templates with JSON data objects, in the browser.
The <body> of the page includes a couple HTML elements that need further explanation:
<body>
<h1>Phones</h1>
<a name="phones" ht-container="phones" ht-href="phones.html" ht-jref="phones.json" ht-repeat ht-class="fade-in" ht-cache></a>
<a name="phone" ht-container="phone" ht-href="phone.html" ht-after="after_phone()" ht-class="fade-in" ht-cache></a>
</body>
Please notice the <a> tags. They contain names and a number of non-standard attributes and attribute-value pairs. All attribute names that begin with "ht-" are relevant to our utility that merges HTML templates with JSON data objects. The merged content is "injected" into that container when displayed. We use this same utility in several of our applications.
<a> tags define hyperlinks. But in this case, they link to themselves, which enables the utility to display the content of that element.
Normally the "content" of a hyperlink is just some brief text. But in this case the link serves as a container for complex DOM objects that are dynamically derived from a merger of HTML and JSON data objects - at runtime.
The "phones" container holds a merger of phones.html and phones.json. Let's take a closer look at the HTML template (phones.html).
</a><div class="d">
<a href="#phone" onclick="get_phone('{{id}}')">
<img class="thumb" src="{{imageUrl}}">
<a class="link" href="#phone" onclick="get_phone('{{id}}')">{{name}}
</a><br><br>{{snippet}}
</div>
Notice the "names" that are delimited by the opening and closing curly braces (i.e. {{id}}, {{name}}, {{imageURL}}, {{snippet}}).
Now go look at the contents of phones.json. See the same names. Our utility maps JSON data values to their corresponding HTML "markers" during the merge according to their names.
Extract:
{
"age": 0, "id": "motorola-xoom-with-wi-fi",
"imageUrl": "http://angular.github.io/angular-phonecat/step-12/app/img/phones/motorola-xoom-with-wi-fi.0.jpg",
"name": "Motorola XOOM\u2122 with Wi-Fi",
"snippet": "The Next, Next Generation\r\n\r\nExperience the future with Motorola XOOM with Wi-Fi, the world's first tablet powered by Android 3.0 (Honeycomb)."
}
The "phones" container has an attribute named "ht-repeat" that instructs the merge to repeat for each element in a JSON array. The merge generates a list! This is an example and type of "declarative" programming, as opposed to the typical procedural syntax that we normally use.
The "ht-cache" attribute instructs the utility to cache the HTML template in the browser rather than making additional requests from the server. It's also possible to cache JSON data objects in the browser, or alternatively request a fresh copy from the server when the container is displayed.
A similar merge occurs when a phone is clicked. That causes the phone details panel to be generated and displayed.
The JavaScript
The JavaScript for this application is stored externally in phonelist.js. I'll break it down and explain it.
window.location.hash = '#phones';
Assigning the name '#phones' to window.location.path is a way to make the phone list appear. It runs when the page is first loaded. Technically "#phones" refers to a DOM object known as an anchor. In this case "#phones" is a reference to the container named "phones". Our utility monitors for window.location.hash changes, then displays that container.
function get_phone(id) {
ht_merge('phone','phone.html','json/' + id + '.json');
}
The get_phone() function may be invoked while the phone list is displayed, when a user clicks the hyperlink or thumbnail image of that phone. It invokes the ht_merge() function that dynamically generates the content in the phone detail container, and shows it.
function after_phone() {
window.scrollTo(0,0);
}
The after_phone() function is invoked when the phone detail container is displayed. It causes the container's content to be scrolled to the top.
function after_image() {
var o = $('ix').getElementsByTagName('IMG')[0];
if (o) $('phone.image').src = o.src;
}
The after_image() function is invoked as the phone detail content is being generated. Included in that content is an array of thumbnail images for the selected phone. The "source" of the first array element is assigned to the large image, which is also in the container.
function thumb_click(t) {
var o = ht_replaceNode($('phone.image'));
o.src = t.src;
o.className='fade-in';
}
The thumb_click() function is invoked when users click on a thumbnail image in the phone detail panel. It replaces the larger image with the source of the thumbnail image.
That's About It
The "phones" application shows some the dynamic capabilities of browser technologies that provide for a rich, fluid end-user experience. It also shows a good balance between client and server roles and interactions. I hope is sparks some interest in browser technologies for traditional IBM i developers.
Continued in Part 7.