json in xpages - kwintessential notes · pdf filejson in xpages ... json or javascript object...
Post on 08-Mar-2018
273 Views
Preview:
TRANSCRIPT
Contents
Introduction............................................................................................................................................. 2
Document version ................................................................................................................................ 2
Terminology ............................................................................................................................................ 2
JSON ........................................................................................................................................................ 2
Example JSON Object ........................................................................................................................... 2
JavaScript classes and objects .............................................................................................................. 3
Example ........................................................................................................................................... 3
Ways to put functions into JSON objects. ......................................................................................... 4
JSON and Domino .................................................................................................................................... 5
NotesView - ReadViewEntries .............................................................................................................. 5
Optional arguments - Outputformat=JSON ....................................................................................... 5
Other sources of JSON in Domino ......................................................................................................... 5
ViewColumn ..................................................................................................................................... 5
Fields ............................................................................................................................................... 6
JSON in XPages ........................................................................................................................................ 7
Use of Scope Variables ......................................................................................................................... 7
Example working on client side with server side data ....................................................................... 7
Example Repeat control ....................................................................................................................... 8
Example Data Table control ................................................................................................................. 9
Example – XAgent that collects column values ................................................................................... 11
Use of REST Service ............................................................................................................................ 14
Step 1 – Set up the REST Service control ......................................................................................... 14
Example Write JSON to field ............................................................................................................... 15
Display the values .......................................................................................................................... 15
Edit the values................................................................................................................................ 17
Result ............................................................................................................................................. 20
Recommended resources ...................................................................................................................... 21
Introduction
This document describes JSON and how the use it with XPages development. On a high level JSON is
described and on a low level the usage within XPages is demonstrated.
After reading this document you, as a developer, should decide if JSON can be beneficial in your projects.
This document might give you guidance in taking the first steps.
Document version
Date Version Author Comments
2013-09-17 0.1 Patrick Kwinten Initial Draft
2013-09-17 0.2 Patrick Kwinten Added JSON in Notes fields
Terminology
Below is a list with technical terms used in througho ut this document:
Term Description
XPages Rapid web and mobile application development
technology.
XAgent Web Agents XPages style.
XPinC XPages in Notes client
SSJS Server-side JavaScript
Extension Library Library that provides additional controls for
XPages.
JSON
From Wikipedia:
JSON or JavaScript Object Notation, is a text-based open standard designed for human-readable data
interchange. It is derived from the JavaScript scripting language for representing simple data structures
and associative arrays, called objects. Despite its relationship to JavaScript, it is language-independent,
with parsers available for many languages.
The JSON format is often used for serializing and transmitting structured data over a network
connection. It is used primarily to transmit data between a server and web application, serving as an
alternative to XML.
Example JSON Object
The following example shows the JSON representation of an object that describes a person. The object
has string fields for first name and last name, a number field for age, an object representing the person's
address and an array of phone number objects.
{
"firstName": "John",
"lastName": "Smith",
"age": 25,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": 10021
},
"phoneNumbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "fax",
"number": "646 555-4567"
}
]
}
JavaScript classes and objects
JavaScript is an object-based language. JSON is an example of that.
Classes can have:
• Properties.
• Methods, e.g. getFullName().
JSON objects can include functions in the same way they can contain arrays and objects. These functions
are then methods of the JSON object.
Objects are created from these classes with the "new" statement.
Example function Person(fName, mName, lName,phone,eMail) {
this.FirstName = (fName) ? fName : “”;
this.MiddleName = (mName) ? mName : “”;
this.LastName = (lName) ? lName : “”;
this.phone = (phone) ? phone : “”;
this.email = (eMail) ? EMail : “”;
this.getFullName = function() {
var tempName = [];
if (this.FirstName != “”) tempName.push(this.FirstName);
if (this.MiddleName != “”) tempName.push(this.MiddleName);
if (this.LastName != “”) tempName.push(this.LastName);
return tempName.join(“ ”);
}
}
You create a new person object as followed:
var p1 = new Person(“Patrick”, “”, “Kwnten”, “188800”, “patrick@facebook.com”);
And use it:
alert(“The person's name is ” + p1.FirstName + “ ” + p1.LastName + “.”);
Ways to put functions into JSON objects.
• In-line as the object is declared:
var myObj = {
myData : “some data goes here”,
myFunct : function (parms) {
// CODE OF THE FUNCTION
this.myData = “some new data is here”;
return something; //optional
}
};
• Externally after the function is declared:
var myObj = {
myData : “some data goes here”
};
myObj.myFunct = function (parms) {
// CODE OF THE FUNCTION
this.myData = “some new data is here”;
return something; //optional
};
JSON and Domino Domino has by default capabilities to produce JSON.
NotesView - ReadViewEntries
Use this command to access view data in XML form without appearance attributes such as fonts, list
separators, date formats, HTML settings, view templates and frame redirections.
Optional arguments - Outputformat=JSON
This argument displays the view in a JavaScript Object Notation format.
In this JSON object there is 1 (toplevel) viewentry node that contains all the entries. Similarly there's only
1 entrydata per document.
In most cases you cannot bind this JSON object directly to a control in XPages. Therefor other
alternatives could be considered.
Other sources of JSON in Domino
In Domino there are other design elements that can produce JSON code:
• View Columns.
• Forms and pages.
• Fields and computed text areas.
• Agents.
• Script libraries.
• File attachments.
o Both in the database and in documents.
• XPages “agents”.
• Server-side JavaScript (XPages only).
• @Formulas.
• LotusScript.
Since this document focuses on the usage of JSON in XPages we will only describe shortly how well
‘traditional’ design elements can be used to produce Notes data as JSON.
ViewColumn
Put the following piece of code (@Formula) into a view column; in _exclude list all items from the
document that should not be included in the output. All items in the document that are not excluded are
used to build a JSON String.
_exclude:="$FILE":"$Fonts":"Form":"$UpdatedBy":"$Revisions":"ID":"ModifiedBy":"AddressInvoiceAppartment";
_fld:=@Trim(@ReplaceSubstring(@DocFields;_exclude;@Nothing));
"{\"@unid\":\""
+@Text(@DocumentUniqueID)+"\","
+ @Implode (
@Transform (
_fld; "_fn" ; "\"" + _fn + "\":\"" + @Text ( @GetField ( _fn) ) + "\"" ) ; "," ) +
"},"
You can retrieve the JSON string e.g. by creating a “XAgent” (see ‘Example – XAgent collects column
values’).
Fields
A JSON object can be stored in a Notes data field as a string.
A use case could be that you have a products catalog with reviews and instead of storing the reviews in
separate review documents (document type = response) you store the reviews on the product document
in one single field. This can save the hassle of cleaning up the database when a product is removed from
the catalog.
To convert the string representation of the JSON data into an actual JSON object the JavaScript eval()
function can be used.
For instance if your JSON is stored on a document in a field called leaguePlayers as a string and it looks as
followed:
{
“players”: [
{“name”:”Dennis Bergkamp”,”club:Arsenal”},
{“name”:”David Beckham”,”club:Manchester United”}
]
}
You can use in the afterPageLoad event of an XPage the following JavaScript code to convert it to a JSON
object:
If (document1.hasItem(“leaguePlayers”)){
viewScope.put(“leaguePlayers”,eval(“(“ + document1.hasItem(“leaguePlayers”)[0] + “)”))
}
Now you can use this viewScope and bind it to e.g. a Repeat control or Data Table control (see examples
in the next chapter).
In your real world product catalog you probably want users to create new reviews or remove the fake
ones. In the next chapter you can find examples for this.
JSON in XPages
XPages focuses mainly on server-side programming. JSON becomes a valid data format for (XPinC) client
and web applications.
It can be created and retrieved by client and server-side code, including during full- and partial updates.
JSON can be used immediately or stored and retrieved from scope variables. It allows extended
flexibility, better responsiveness and fewer updates.
Stored JSON can contain arrays of objects used to define and control repeats.
Use of Scope Variables
In the most common cases you want to bind the JSON object (directly) to a control, e.g. repeat control or
data table control.
In case your JSON data is stored somewhere as a string, this string has to be converted to an object first
via the JavaScript eval() function. In such case the JSON object needs to be created before the page is
displayed. This can be done by using a viewScope variable and store the evaluated JSON object here. The
value of the viewScope is computed in the beforeRenderResponse event.
Example working on client side with server side data
When you want to work with a JSON object on the client side that is created with data gathered by
server side code you can use store it first in a scope variable:
var sPlayers = "{'name':'Bergkamp','country':'Netherlands'},{'name':'Zlatan','country':'Sweden'},{'name':'Beckham','country':'England'}";
applicationScope.put("AllTimeFavorites",sPlayers);
On the client side you can retrieve the value as followed:
var sAllTimeFavorites='#{javascript:applicationScope.AllTimeFavorites}';
The variable "sAllTimeFavorites" is holding the value as a string. We need to evaluate the
string/expression to convert it as a JSON object so that the client-side JavaScript can process it:
var objFavorites=eval("(["+sAllTimeFavorites+"])";
Since the eval() function is not recommended due to performance reasons, there is another way to
achieve the same result:
var objFavorites=[#{javascript:applicationScope.AllTimeFavorites}];
The only difference is that the SSJS is not enclosed inside quotes.
Example Repeat control
A common practice us to bind a Repeat control to a Scoped Variable that contains the JSON object:
Note: the viewScope ‘productOrders’ is set at the afterPageLoad event of the XPage.
The collection name (here: jDataRow) is then used within the Repeat control as reference to a specific
element in each entry via dot notation e.g.
<xp:inputText id="inputText8" value="#{jDataRow.product}"/>
Example Data Table control
Binding a Data Table control to a Scoped Variable that contains a JSON object is very similar to the
process for a Repeat control. Nevertheless follows here a description.
Note: the viewScope ‘productOrders’ is set at the afterPageLoad event of the XPage.
The collection name (here: jDataRow) is then used within the Data Table control as reference to a
specific element in each entry via dot notation e.g.
<xp:text value="#{javascript:jDataRow.product}" id="docProdName" />
Example – XAgent that collects column values
The XAgent uses a ViewNavigator for fast retrieval of the column entries. The real magic is the use of
java.lang.StringBuilder() to concat the view entries. A stringBuilder is the fastest way to concat a large
number of strings. It is faster than just to use string1 + string2.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
<xp:this.afterRenderResponse><![CDATA[#{javascript:try{
var externalContext = facesContext.getExternalContext();
var writer = facesContext.getResponseWriter();
var response = externalContext.getResponse();
// Set content type
response.setContentType("application/json");
response.setHeader("Cache-Control", "no-cache");
var json:java.lang.StringBuilder = new java.lang.StringBuilder();
var v:NotesView = database.getView("($jsonContact)");
//do not do AutoUpdates
v.AutoUpdate = false;
var nav:NotesViewNavigator = v.createViewNav();
nav.setEntryOptions(
NotesViewNavigator.VN_ENTRYOPT_NOCOUNTDATA);
//enable cache for max buffering
nav.BufferMaxEntries = 400
var entry:NotesViewEntry = nav.getFirst();
while (entry != null) {
json.append( entry.getColumnValues().elementAt(0).toString());
var tmpentry:NotesViewEntry = nav.getNext(entry);
entry.recycle();
entry = tmpentry;
}
writer.write('[' + @Left(json.toString(), @Length(json.toString()) - 1) + ']');
writer.endDocument();
} catch(e){
_dump(e);
}}]]>
</xp:this.afterRenderResponse>
</xp:view>
You can enhance performance in case you fetch the column values with Java:
public class ViewColumn {
private static final String MSG_STRING_ERROR = "ERROR: ";
private static final String MSG_STRING_NOT_FOUND = " not found";
public ViewColumn() {
}
public String getViewColumnValueJSON(String viewname, int pos) {
ViewNavigator nav = null;
StringBuilder json = new StringBuilder();
json.append('[');
String strValue = "";
try {
View view = getCurrentDatabase().getView(viewname);
if (null != view) {
view.setAutoUpdate(false);
nav = view.createViewNav();
nav.setEntryOptions(ViewNavigator.VN_ENTRYOPT_NOCOUNTDATA);
nav.setBufferMaxEntries(400);
ViewEntry entry = nav.getFirst();
while (entry != null) {
json.append( entry.getColumnValues().elementAt(pos).toString());
ViewEntry tmpentry= nav.getNext(entry);
entry.recycle();
entry = tmpentry;
}
strValue = json.toString();
strValue = strValue.substring(0, strValue.lastIndexOf(",")) + "]";
view.setAutoUpdate(true);
} else {
System.out.println(MSG_STRING_ERROR + viewname + MSG_STRING_NOT_FOUND);
}
} catch (NotesException e) {
System.out.println(MSG_STRING_ERROR);
strValue = "[{}]";
}
return strValue;
}
}
Another tip: in case you want to jump to a specific row in the ViewNavigator you can use the skip()
method e.g.
int start=50;
//try to skip 50 entries and return the entries actually skipped
int skippedEntries = viewNav.skip(start);
if (skippedEntries==start) {
//read the current entry after the skip operation
ViewEntry currEntry=viewNav.getCurrent();
//work with currEntry
//...
currEntry.recycle();
}
Use of REST Service
The Extension Library provides a REST Service control to expose REST services. The service
viewJsonService provides the content of a view in JSON format. The service viewJsonLegacyService
provides the content of a view in JSON format similar to the ?ReadViewEntries&OutputFormat=JSON
NotesView parameter.
The viewJsonService is designed to interact with front-end components (i.e. JavaScript widgets making
AJAX calls to retrieve the JSON from the service). Repeat controls are back-end controls that are typically
just bound directly to a data source or other server-side abstraction layer.
In the following description we will demonstrate the usage the viewJsonService service in combination
with the Dojo Data Grid control, another control available in the Extension Library. We will display the
‘Name’ column of the view ‘People’ in the names.nsf in the grid.
Step 1 – Set up the REST Service control
• Create an XPage and drag onto it the REST Service control (available in the Data Access section).
o In Properties All Properties \basics give the pathInfo property the value of ‘names’. This
value together with the XPage name will be the reference of the service e.g.
server/path/filename/demo.xsp/names.
o In Properties All Properties \basics\service select the xe:viewJsonService option.
� Set the following properties:
• databaseName = ‘names.nsf’.
• viewName = ‘People’.
� Add a column property (plus sign) and set the following properties:
• columnName = ‘Name’ (name of a real column in this view).
• name = Names (this will be the programmatic reference to the column
value).
• Drag a Dojo Data Grid control (available in the Dojo Layout section) on your XPage.
o In Properties All Properties \data section set the property for storeComponentId to the
id of your REST Service control e.g. restService1. This id is available in a dropdown list.
• Drag in a Dojo Data Grod Column control (same section) in the grid.
o In Properties All Properties \data section set the property for field to the programmatic
name of the column you set earlier (in this example ‘Names’).
If you preview the XPage the result should look something like this:
Note: The combination lastname/firstname separated by a comma is set by a column formula in the
view.
A (probably complete) description on using the grid control in combination with the viewJsonService has
been written by Brad Balassaitis (see recommended resources).
Below is the code of the example XPage:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xe="http://www.ibm.com/xsp/coreex">
<xe:restService id="restService1" pathInfo="names">
<xe:this.service>
<xe:viewJsonService databaseName="names.nsf" viewName="People">
<xe:this.columns>
<xe:restViewColumn columnName="Name" name="Names"></xe:restViewColumn>
</xe:this.columns></xe:viewJsonService>
</xe:this.service>
</xe:restService>
<xe:djxDataGrid id="djxDataGrid1" storeComponentId="restService1">
<xe:djxDataGridColumn id="djxDataGridColumn1" field="Names">
</xe:djxDataGridColumn>
</xe:djxDataGrid>
</xp:view>
Example Write JSON to field
In a previous example you saw how that you can create a JSON object from a string stored in a Notes
field and bind that object to a Repeat control.
The changes are high that you want to update the content of that field too.
Let’s take our previous example with football players and their (favorite) team.
Display the values
Here a short rerun of the basics.
A field contains the JSON as a string. In the afterPageLoad event of the XPage the string is converted to
an object and stored in a viewScope variable:
If (document1.hasItem(“leaguePlayers”)){
viewScope.put(“leaguePlayers”,eval(“(“ + document1.hasItem(“leaguePlayers”)[0] + “)”))
}
A Repeat control uses this viewScope as data-binding source. The Repeat control contains 2 fields to
display the fields of the JSON object and a button to remove a single object.
Here is what our XPage looks like. Note it contains two other fields, to store some data for the Notes
document.
The code looks like as followed:
<xp:table border="0" style="width:100.0%;margin-left:-240px">
<xp:tr>
<xp:td style="width:100px"><xp:label value="Competition:" id="Competition"></xp:label></xp:td>
<xp:td><xp:inputText id="inputText1" value="#{document1.leagueName}" style="width:200px"></xp:inputText></xp:td>
</xp:tr>
<xp:tr>
<xp:td>
<xp:label value="Description:" id="label4"></xp:label></xp:td>
<xp:td><xp:inputTextarea id="inputTextarea1" value="#{document1.leagueDescription}"
style="width:200px;height:60px"></xp:inputTextarea></xp:td>
</xp:tr>
<xp:tr>
<xp:td></xp:td>
<xp:td>
<xp:panel>
<xp:table>
<xp:tr>
<xp:td style="width: 200px"><xp:label value="Name:" id="label1" style="font-weight:bold"></xp:label></xp:td>
<xp:td style="width: 200px"><xp:label value="Club:" id="label2" style="font-weight:bold"></xp:label></xp:td>
</xp:tr>
<xp:repeat id="repeat1" rows="30" value="#{viewScope.leaguePlayers}" var="data" indexVar="index">
<xp:tr>
<xp:td style="width: 200px"><xp:text escape="true" id="computedField2" value="#{data.name}"></xp:text></xp:td>
<xp:td style="width: 200px"><xp:text escape="true" value="#{data.club}" id="computedField1"></xp:text></xp:td>
</xp:tr>
</xp:repeat>
</xp:table>
</xp:panel>
</xp:td>
</xp:tr>
</xp:table>
Edit the values
In order to edit the values we change the Computed Field controls to Edit Box controls and we add a Link
control to remove a single object in the JSON object. Of course you want to save your changes
ultimately.
Edit Box control: <xp:inputText id="inputText8" value="#{data.name}" style="width: 200px"></xp:inputText>
Save Button control
This Button control has 2 actions:
• Get the values from the viewScope variable, convert the object to a string and sets the value in a
Notes field.
• Save the Notes document.
<xp:button value="Save" id="button1">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete" immediate="false" save="false">
<xp:this.action>
<xp:actionGroup>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:var tmpPlayers = viewScope.get("leaguePlayers");
if (tmpPlayers != null){
var stringValue = "[";
for(var a=0;a<tmpPlayers.length;a++){
stringValue += "{";
for(var i in tmpPlayers[a]){
if(tmpPlayers[a][i] == null){tmpPlayers[a][i]=""};
stringValue += "\"" + i + "\":\"" + tmpPlayers[a][i] + "\",";
}
stringValue = stringValue.slice(0,-1);
stringValue += "},";
}
stringValue = stringValue.slice(0,-1);
stringValue += "]";
document1.setValue("leaguePlayers",stringValue);
}}]]></xp:this.script>
</xp:executeScript>
<xp:saveDocument var="document1"></xp:saveDocument>
</xp:actionGroup>
</xp:this.action>
</xp:eventHandler>
</xp:button>
Remove Link control
The remove Link control removes a single object, corresponding to the index name (index) of the Repeat
control, from the object in the viewScope variable. The splice() method is used for this.
var Players = viewScope.get("leaguePlayers");
if (Players.length > 1) {
//Create new temporary object from the object but without selected item
var tmpPlayers = Players.splice(index,1);
var tmpPlayersLength = tmpPlayers.length;
viewScope.put("tmpPlayersLength", tmpPlayersLength);
//Create new string from temporary object
var stringValue = "[";
for (var a = 0; a < tmpPlayers.length; a++){
stringValue += "{";
for (var i in tmpPlayers[a]) {
if (tmpPlayers[a][i] == null) {
tmpPlayers[a][i] = "";
};
stringValue += "\"" + i + "\":\"" + tmpPlayers[a][i] + "\",";
}
stringValue = stringValue.slice(0,-1);
stringValue += "},";
}
stringValue = stringValue.slice(0, -1);
stringValue += "]";
//Create a new object from the string
var objPlayers = eval("(" + stringValue + ")");
viewScope.put("leaguePlayers",objPlayers);
} else {
viewScope.put("leaguePlayers",eval("(\[\{\"name\":\"\" , \"club\":\"\"\}\]\)"));
}
Add Player Button control
In order to store more than 1 object in the JSON object we need to add a control. Basically the control
will add a new object to the JSON object in the viewScope and give it empty values by default.
var Players = viewScope.get("leaguePlayers");
if (Players != null){
//Create string from current object
var stringValue = "[";
for(var a=0;a<Players.length;a++){
stringValue += "{";
for(var i in Players[a]){
if(Players[a][i] == null){Players[a][i]=""};
stringValue += "\"" + i + "\":\"" + Players[a][i] + "\",";
}
stringValue = stringValue.slice(0,-1);
stringValue += "},";
}
//Add a new object with empty values as a string
stringValue += "{\"name\":\"\" , \"club\":\"\"\}\]";
//Create new object via eval() function
var objPlayers = eval("(" + stringValue + ")");
viewScope.put("leaguePlayers",objPlayers);
}else{
viewScope.put("leaguePlayers", eval("(\[\{\"name\":\"\" , \"club\":\"\"\}\]\)"))
}
Result
Below you can see how the result looks like:
Recommended resources
Below you can find an overview of recommended sources of information.
Title Author
JMP303 JSON in client- and server-side code
Master Class (Lotusphere 2011) (link)
Scott Good
Use @Transform to build JSON and consume the
output in an XAgent (link)
Ulrich Krause
Use JSON to Create Flexible, Scalable, and Easy-
to-Use Data Storage in XPages (link)
Kathy Brown
Dojo Data Grids (link) Brad Balassaitis
top related