Building JSR-286 portlets using AngularJS and IBM Web

Transcription

Building JSR-286 portlets using AngularJS and IBM Web
Building JSR-286 portlets using AngularJS and IBM Web
Experience Factory
Overview
This article illustrates how to build JSR-286 portlets using AngularJS framework and IBM Web Experience Factory
(WEF) for WebSphere Portal
Before going any further let us understand the drivers for integrating AngularJS with Web Experience Factory.
AngularJS is a UI framework to build web applications. AngularJS relies on available REST / AJAX services to
consume data from and build a user interface.
Web Experience Factory is a rapid development tool for building web applications including portlets. WEF provides
builders for end-to-end application development including both user interface and back-end services.
Thus where AngularJS and Web Experience Factory complement each other are when you would want to use WEF’s
capability to expose back-end services as REST services while at the same time use AngularJS framework to build
the UI for the portlet. Following could be some of the drivers to integrate these technologies.

Leverage WEF to expose complex existing services as REST services in an application. For e.g. expose
JDBC / Web Service calls as REST service in Portal for AngularJS to consume to build the portlet UI.

Leverage the XML/JSON data massaging builder/capabilities of WEF to format / aggregate data from
multiple service calls in the desired output before exposing it via a single REST service.

Use AngularJS to code the User Interface for a portlet that resides with other WEF portlets in a portal
application.
Note: If you have REST services exposed for your back-end application by some other tool and you simply want to
consume these REST services to develop an AngularJS web application that you may want to expose as a portlet
then consider IBM Script portlet as an option. (Refer to the article: Import Single Page Applications to a Script Portlet
Instance)
Target Audience
This article is intended for AngularJS developers who are looking to build portlets and utilize their AngularJS
knowledge while leveraging Web Experience Factory software automation. The article provides a high level overview
of how to expose back-end services as REST services using WEF and build the portlet UI using AngularJS.
This article is not intended to be an introduction / tutorial for either AngularJS or Web Experience Factory.
Pre-requisites
Web Experience Factory 8.5 or higher
Script Application builder
XML File Data Service Builder
AngularJS
Application Overview
This article provides a high level overview of building a simple multi-page application / portlet using AngularJS and
Web Experience Factory.
The application illustrates the functionality of viewing / editing a Contact List in a portlet hosted on WebSphere Portal.
As the portlet is rendered, it displays the contact list as shown in the figure below.
The user can click on the contact name and can view/edit the contact information (see figure below)
Building the Service Layer


Create a Web Experience Factory project in the Eclipse based Designer.
For the purpose of this article, assume that you have the contact list data in an xml file say contacts.xml in
the following format.
<contacts>
<contact>
<id>EMP981029</id>
<name>Samantha Daryn</name>
<extension>49404</extension>
<location>Chicago</location>
<title>Vice President</title>
<photo>/images/SamanthaDaryn.jpg</photo>
<email>daryn981029@xyzmail.com</email>
</contact>
<contact>
<id>EMP981030</id>
<name>Lucille Suarez</name>
<extension>29184</extension>
<location>Berlin</location>
<title>Director</title>
<photo>/images/LucilleSuarez.jpg</photo>
<email>suarez981030@xyzemail.com</email>
</contact>
.
.
</contacts>

Create a Model in Web Experience Factory (say ContactsProvider) and Import the xml file in the model
using the Xml File Data Service builder. Make the “id” as the Key Field in the builder
The XML File Data Service builder will generate CRUD service operations for the contact list.
Note: XML File Data Service builder is meant only for prototyping and building quick samples. DO NOT use
this builder in production applications.
Building the UI Model Skeleton integrated with AngularJS

Create a new Model in Web Experience Factory (say Contacts) and add the Script Application builder to the
model.
The Script Application builder imports the Service Provider model (ContactsProvider.model developer in
previous step in this case) and generates REST Service URLs for each of the CRUD operations in the Service
Provider. The builder also adds a JSON variable in the head of the generating HTML page which contains the
REST Service URL that can be accessed by any JavaScript code.

The Script Application builder requires a HTML page which would act as a template for the resulting
application. For this Application create a HTML file (say main.html) with the following HTML code and
import it in the Script Application builder by the name of contactsPage
<html>
<head>
<title>Contacts</title>
</head>
<body>
<div ng-app='myAngularApp' ng-controller='ContactsController'>
<div ng-switch="viewState">
<div id="contactList" />
<div id="contactEdit" />
</div>
</div>
<script
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.27/angular.mi
n.js"></script>
<span name="controller" />
</body>
</html>
The ng-app and ng-controller for AngularJS tag have been added to the div tag which encloses the entire
portlet application.
The div with id “contactList” and “contactEdit” will be superimposed with the list page and edit page
respectively in the model.
The ng-switch attribute for AngularJS will be used to switch between the contacts list view and contact edit
view in further steps.
Tip: Add the ng-app and ng-controller attributes for AngularJS to a div tag not to the html or body tag in
your portlet html since those tags would get stripped out when you add the portlet on a Portal Page.

Next create a JavaScript file (say controller.js) with the following code.
var app = angular.module('myAngularApp', []);
console.log('Entering Contoller');
app.controller('ContactsController', ['$scope', '$http', '$window',
function($scope, $http, $window)
{
$scope.serviceRestUrls = $window.serviceRestUrls;
}
});
Note: The AngularJS controller adds the serviceRestUrls JSON object created by Script Application
builder which contains the REST service URLs to its scope.

Add the above created JavaScript file to the contactsPage using the Client JavaScript builder on the
“controller” div tag.

Add the Portlet Adapter builder to the model and deploy the project to WebSphere Portal. Add the portlet to
a Portal Page. You will see a blank portlet as of now. The browser console log should show the “Entering
Controller’ message.
Creating the Contacts List View

Add the following AngularJS code to controller.js file to fetch the list of contacts via a REST Query.
$scope.getContacts = function()
{
// Set Visibility for the div
$scope.viewState = 'list';
$http.get(serviceRestUrls.getContactsURL).then(function(resp)
{
console.log('Success', resp);
// For JSON responses, resp.data contains the result
$scope.contacts = resp.data.contacts.contact;
}, function(err) {
console.error('ERR', err);
// err.status will contain the status code
});
};
getContacts();
Note: The above code makes REST service call to get all the contacts in a JSON object named contacts. Also
the code sets the viewState to list

Create a separate html file (say list.html) which contains the html markup for the contact list section with the
following html code.
<div id="listView" ng-switch-when="list">
<div id="title"><h1>Contacts List</h1></div>
<ul>
<li name="DataContainer" ng-repeat='contact in contacts'>
<table>
<tr><td>
<img ng-src='{{getImage(contact.photo)}}'></img>
</td></tr>
<tr><td align="center">
<span name="Name" class="outputData">
<a href="#" ng-click="getContactbyId(contact.id)">
<div>{{contact.name}}</div><div>{{contact.title}}
</div>
</a>
</span>
</td></tr>
</table>
</li>
</ul>
</div>
Note: the above html section rendered only when viewState is set to list. The rest of the html code simply renders
the JSON object contacts; on the page. The contact name is a link which calls getContactbyId(id) function that you
will be adding when you build the Contact Edit View.

Import the above created page in your UI model using Imported Page builder and name it as
contactsListPage

Insert the contactsListPage created in the previous step on the “contactList” div tag of the
contactsListPage using the Inserted Page builder.
This completes the creating the contacts list view. Next you will be creating the Contact Edit View section.
Creating the Contact Edit View

Create a separate html file (say edit.html) which contains the html markup for the contact edit section.
<div ng-switch-when="detail">
<div id="title"><h1>Edit Contact Details</h1></div>
<div align="center">
<form name="editContactForm" ng-submit="updateContact(editContactForm.$valid)">
<table>
<tr>
<td colspan="2" align="center">
<img ng-src='{{getImage(contactDetail.photo)}}'></img>
</td>
</tr>
<tr>
<td class="label">Name:</td>
<td>
<input name='name' ng-model='contactDetail.name' required>
<p ng-show="editContactForm.name.$invalid" class="help">
Name is required.
</p>
</td>
</tr>
<tr>
<td class="label">Title:</td>
<td>
<input name='title' ng-model='contactDetail.title'>
</td>
</tr>
<tr>
<td class="label">Extension:</td>
<td>
<input type='email' name='email' ng-model='contactDetail.extension>
</td>
</tr>
<tr>
<td class="label">Email:</td>
<td>
<input type='email' name='email' ng-model='contactDetail.email' >
</td>
</tr>
<tr>
<td class="label">Location:</td>
<td>
<input type='email' name='email' ng-model='contactDetail.location>
</td>
</tr>
</table>
<button ng-click="getContacts()">Cancel</button>
<button type="submit" ng-disabled="editContactForm.$invalid">Save</button>
</form>
Note: The above html section is rendered only when viewState is set to detail. Pay attention to the AngularJS tags
</div>
in the html for form validation and form submission.
</div>

Import the above created page in your UI model using Imported Page builder and name it as
contactEditPage. Insert the contactEditPage on the “contactEdit” div tag of the contactsListPage
using Inserted Page builder.

Next, add the following functions to controller.js file to get a single contact by id (getContactbyId) and to
update an existing contact (updateContact).
$scope.getContactbyId = function(id)
{
// Set Visibility for the div
$scope.viewState = 'detail';
$http.get(serviceRestUrls.getContactURL, {params:{"id":
id}}).then(function(resp) {
// For JSON responses, resp.data contains the result
$scope.contactDetail = resp.data.contact;
}, function(err) {});
};
$scope.updateContact = function(valid)
{
$http({
method: 'POST',
url: serviceRestUrls.updateContactURL,
headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'},
params : $scope.contactDetail
});
// get list of updated contacts
$scope.getContacts();
};
This completes the steps required to build the Contacts List Application.
About the Authors
Abhishek Singh (abhisheks@us.ibm.com) is a Senior IT Architect with IBM Software Services for WebSphere. He
has over 15 years of IT experience specializing in delivery of Portal and Mobile Application development with focus
on SOA, Analytics, Content Management Systems, Responsive UI design and enterprise Java/ JEE applications. His
experience includes designing and developing software products, service- oriented architecture, information systems,
telecom applications, and client/server applications.
Nischitha Rai (nyrai@us.ibm.com) is a Managing Consultant working with IBM Software Services for WebSphere.
She has 9 years of experience working on several WebSphere Portal and JAVA/JEE application development
engagements. Her expertise is in WebSphere Portal, WebSphere Experience Factory and Web Content Manager.