JQM & Domino Data Service (3)

In a previous post I demonstrated how to populate a listview for jQuery Mobile from a Notes view via Domino Data Service. In this post I will show how to include a ‘More’ button to load additional loading of more items for the listview and display them.

Screenshot_1

For this you need to make changes in 2 places:

  • mobile.xsp
  • employeelist.js

employeelist.js

In the JavaScript file we need to modify the initial getEmployeeList function and include a new function to load more employees from the list. This function is called from the button on the employeeListPage.

function getEmployeeList() {
$.getJSON(serviceURL + ‘data/collections/name/People?count=20‘, function(data) {
$(‘#employeeList li’).remove();
employees = data;
$.each(employees, function(index, employee) {
var tmp = “”;
tmp+=’<li>’;
tmp+=’<a href=”mobile_person.xsp?id=’ + employee["@unid"] + ‘”>’ +
‘<img src=”http://greenhouse.lotus.com/plugins/plugincatalog.nsf/NoPhotoPerson.gif”/>&#8217;;
tmp+=’<h4>’ + employee.$17 + ‘</h4>’;
tmp+=’<p>’ + employee.CompanyName + ‘</p>’;
if (employee.$12!=””) {
tmp+=’<span class=”ui-li-count”>’ + employee.$12 + ‘</span>’;
}
tmp+=’</a></li>’;
$(‘#employeeList’).append( tmp );
});
$(‘#employeeList’).listview(‘refresh’);
});
}

function getMoreEmployeeList(num) {
var n = $(‘#employeeList li’).length;
$.getJSON(serviceURL + ‘data/collections/name/People?start=’ + n + ‘&count=’ + num, function(data) {
employees = data;
$.each(employees, function(index, employee) {
var tmp = “”;
tmp+=’<li>’;
tmp+=’<a href=”mobile_person.xsp?id=’ + employee["@unid"] + ‘”>’ +
‘<img src=”http://greenhouse.lotus.com/plugins/plugincatalog.nsf/NoPhotoPerson.gif”/>&#8217;;
tmp+=’<h4>’ + employee.$17 + ‘</h4>’;
tmp+=’<p>’ + employee.CompanyName + ‘</p>’;
if (employee.$12!=””) {
tmp+=’<span class=”ui-li-count”>’ + employee.$12 + ‘</span>’;
}
tmp+=’</a></li>’;
$(‘#employeeList’).append( tmp );
});
$(‘#employeeList’).listview(‘refresh’);
});
}

mobile.xsp

In the xsp file we add a button below the listview in the employeeListPage:

<div id=”employeeListPage” data-role=”page”>

<div data-role=”header” data-position=”fixed”>
<h1>Pretenders Directory</h1>
</div>

<div data-role=”content”>
<ul id=”employeeList” data-role=”listview”
data-filter=”true”>
</ul>
</div>
<xp:button value=”More…” id=”button1″>
<xp:this.attrs>
<xp:attr name=”data-role” value=”button”></xp:attr>
</xp:this.attrs>
<xp:eventHandler event=”onclick” submit=”false”>
<xp:this.script><![CDATA[getMoreEmployeeList(20)]]></xp:this.script>
</xp:eventHandler>
</xp:button>
</div>

 

Addition

You can make it nicer if you add instead the following link/button:

<a id=”btnMore” onClick=”getMoreEmployeeList()” data-role=”button” class=”ui-disabled”>More</a>;

And update the employeelist.js:

//var serviceURL = “http://dev1//apps/fakenames.nsf/api/&#8221;;
//use relative URL instead
var serviceURL = “./api/”;
var count = 20;
var employees;

$(‘#employeeListPage’).bind(‘pageinit’, function (event) {
getEmployeeList();
});

function getEmployeeList() {
$.getJSON(serviceURL + ‘data/collections/name/People?count=’ + count, function (data) {
$(‘#employeeList li’).remove();
employees = data;
$.each(employees, function (index, employee) {
var tmp = “”;
tmp += ‘<li>’;
tmp += ‘<a href=”mobile_person.xsp?id=’ + employee["@unid"] + ‘”>’ +
‘<img src=”http://greenhouse.lotus.com/plugins/plugincatalog.nsf/NoPhotoPerson.gif”/>&#8217;;
tmp += ‘<h4>’ + employee.$17 + ‘</h4>’;
tmp += ‘<p>’ + employee.CompanyName + ‘</p>’;
if (employee.$12 != “”) {
tmp += ‘<span class=”ui-li-count”>’ + employee.$12 + ‘</span>’;
}
tmp += ‘</a></li>’;
$(‘#employeeList’).append(tmp);
});
$(‘#employeeList’).listview(‘refresh’);
$(‘#btnMore’).removeClass(‘ui-disabled’);
//$(‘#btnMore’).attr(“disabled”, “disabled”);
//$(‘#button2′).attr(“disabled”, “disabled”);
});
}

function getMoreEmployeeList() {
$(‘#btnMore’).addClass(‘ui-disabled’);
var n = $(‘#employeeList li’).length;

var num = count;
//var num = $.getUrlVar(‘count’);
$.getJSON(serviceURL + ‘data/collections/name/People?start=’ + n + ‘&count=’ + num, function (data) {
employees = data;
$.each(employees, function (index, employee) {
var tmp = “”;
tmp += ‘<li>’;
tmp += ‘<a href=”mobile_person.xsp?id=’ + employee["@unid"] + ‘”>’ +
‘<img src=”http://greenhouse.lotus.com/plugins/plugincatalog.nsf/NoPhotoPerson.gif”/>&#8217;;
tmp += ‘<h4>’ + employee.$17 + ‘</h4>’;
tmp += ‘<p>’ + employee.CompanyName + ‘</p>’;
if (employee.$12 != “”) {
tmp += ‘<span class=”ui-li-count”>’ + employee.$12 + ‘</span>’;
}
tmp += ‘</a></li>’;
$(‘#employeeList’).append(tmp);
});
$(‘#employeeList’).listview(‘refresh’);
$(‘#btnMore’).removeClass(‘ui-disabled’);
});
}

$.extend({
getUrlVars: function () {
var vars = [],
hash;
var hashes = window.location.href.slice(window.location.href.indexOf(‘?’) + 1).split(‘&’);
for (var i = 0; i < hashes.length; i++) {
hash = hashes[i].split(‘=’);
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
},
getUrlVar: function (name) {
return $.getUrlVars()[name];
}
});

Then the More button get’s disabled / enabled during loading of the data

Tagged with: , ,
Posted in Mobile

JQM & Domino Data Service (2)

In a previous post I demonstrated how to use Domino Data Service (as part of Domino Access Service) to populate a listview for jQuery Mobile. Probably the real-world application you want to mobilize has multiple layers of data that is common in Notes (multiple forms & views). I followed Christophe Coenraets’s example and re-used it for the fakenames application.

First let me show you what you get:

Screenshot_1

 

Screenshot_2

 

At first an overview of the People’s view is presented, from here the user can open the Person details page. In Christophe’s example you can find a more nested navigation but our fakenames application is not setup like that.

What this demo includes:

  • 2 XPages; eg people.xsp and person.xsp.
  • Your modified version of employeelist.js and employeedetails.js in the download from Christophe page.
  • The CSS files in the download from Christophe page.
  • The jQuery JS files in the download from Christophe page.

For convenience I have dropped the files from the download via the Package Explorer in the WebContent folder of the fakenames application. In case you want to mobilize your fakenames application a step further e.g. by packaging it via PhoneGap to access device native api’s you don’t want to store these files here and you don’t want to use XPages to render the HTML.

Of course we assume you have Domino Access Service enabled for the Domino server and the fakenames application.

XPage people.xsp & person.xsp

These files do not differ from the index.html and employeedetails.html files in the download from Christophe page. In case you use XPages you should consider to turn of Dojo and Themes.

JS files employeelist.js & employeedetails.js

Since we will provide the information via Domino Data Service these JS files will be altered. Below you find their code:

employeelist.js

var serviceURL = “http://dev1//apps/fakenames.nsf/api/&#8221;;

var employees;

$(‘#employeeListPage’).bind(‘pageinit’, function(event) {
getEmployeeList();
});

function getEmployeeList() {
$.getJSON(serviceURL + ‘data/collections/name/People?count=1000′, function(data) {
$(‘#employeeList li’).remove();
employees = data;
$.each(employees, function(index, employee) {
var tmp = “”;
tmp+=’<li>’;
tmp+=’<a href=”person.xsp?id=’ + employee["@unid"] + ‘”>’ +
‘<img src=”http://greenhouse.lotus.com/plugins/plugincatalog.nsf/NoPhotoPerson.gif”/>&#8217;;
tmp+=’<h4>’ + employee.$17 + ‘</h4>’;
tmp+=’<p>’ + employee.CompanyName + ‘</p>’;
if (employee.$12!=””) {
tmp+=’<span class=”ui-li-count”>’ + employee.$12 + ‘</span>’;
}
tmp+=’</a></li>’;
$(‘#employeeList’).append( tmp );
});
$(‘#employeeList’).listview(‘refresh’);
});
}

Walkthrough

At the page initiation the function getEmployeeList is called. This makes an Ajax request to the REST API of Domino Data Service and a document collection with the first 1000 entries (if available) in the view named People is being called.

I have not taken a look yet how to implement lazy loading or appending additional document collection(s) when scrolling. If you happen to know how to implement such function please drop me a line here or send me an email.

Then list items in the employee ID element on the Xpage people.xsp are removed (when available) and we loop through the results returned by Domino. We create a new list and establish a hyperlink to people.xsp and add the UNID of the document as parameter.

At last the result is appended to the (emptied) employee ID element and the listview is being refreshed. Wow! You got now a nice list of persons in the directory.

employeedetails.js

$(‘#detailsPage’).live(‘pageshow’, function(event) {
var id = getUrlVars()["id"];
$.getJSON(serviceURL + ‘data/documents/unid/’+id, displayEmployee);
});

function displayEmployee(data) {
var employee = data;
console.log(employee);
$(‘#employeePic’).attr(‘src’, ‘http://greenhouse.lotus.com/plugins/plugincatalog.nsf/NoPhotoPerson.gif&#8217;);
$(‘#fullName’).text(employee.FirstName + ‘ ‘ + employee.LastName);
$(‘#employeeTitle’).text(employee.Title);
$(‘#city’).text(employee.OfficeCity);
console.log(employee.officePhone);
if (employee.Manager) {
$(‘#actionList’).append(‘<li><h3>Manager</h3><p>’ + employee.Manager + ‘</p></li>’);
}
if (employee.InternetAddress) {
$(‘#actionList’).append(‘<li><a href=”mailto:’ + employee.InternetAddress + ‘”><h3>Email</h3>’ +
‘<p>’ + employee.InternetAddress + ‘</p></a></li>’);
}
if (employee.OfficePhoneNumber) {
$(‘#actionList’).append(‘<li><a href=”tel:’ + employee.OfficePhoneNumber + ‘”><h3>Call Office</h3>’ +
‘<p>’ + employee.OfficePhoneNumber + ‘</p></a></li>’);
}
if (employee.CellPhoneNumber) {
$(‘#actionList’).append(‘<li><a href=”tel:’ + employee.CellPhoneNumber + ‘”><h3>Call Cell</h3>’ +
‘<p>’ + employee.CellPhoneNumber + ‘</p></a></li>’);
$(‘#actionList’).append(‘<li><a href=”sms:’ + employee.CellPhoneNumber + ‘”><h3>SMS</h3>’ +
‘<p>’ + employee.CellPhoneNumber + ‘</p></a></li>’);
}
$(‘#actionList’).listview(‘refresh’);
}

function getUrlVars() {
var vars = [], hash;
var hashes = window.location.href.slice(window.location.href.indexOf(‘?’) + 1).split(‘&’);
for(var i = 0; i < hashes.length; i++){
hash = hashes[i].split(‘=’);
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
}

Walkthrough

The idea behind the details page is similar to the people’s list, except we have now a single object in the JSON.

First the ID provided by the parameter is abstracted from the URL and used in the call to a document source via the Domino Data Service.

From the result a set of details is abstracted and presented to the user. Some HTML5 attributes are used to deliver a more native behavior when clicking anchor links (telephone, mail, SMS).

Some thoughts

jQuery Mobile and Domino Access Service provide good foundations for creating mobile Web apps on Domino. However I am a bit thoughtful on the speed of Domino Access Service. If you happen to know how to speed up performance for this please drop a line here.

In a next post I will write the implementation of CRUD actions with jQuery and DDS.

 

Tagged with: , , ,
Posted in AJAX, jQuery, JSON, Lotus Domino, Mobile

listview in JQuery Mobile via Domino Access Service

Here follows an quick example how to create a listview in JQM created with data from a view via DAS. As data source I have used the infamous Fake Names Address book which you can (still) can find on Codestore.

In the example you can navigate between the view (People view) and details (Person view).

people_view

person_view

I have not really find out (yet) how to add the next set of documents when you scroll down the list (to be continued, or drop the solution in the comments or send me an email).

<?xml version=”1.0″ encoding=”UTF-8″?>
<xp:view xmlns:xp=”http://www.ibm.com/xsp/core”&gt;
<xp:this.data>
<xp:dominoView databaseName=”apps\fakenames.nsf”
viewName=”People” var=”viewPeople”>
</xp:dominoView>
</xp:this.data>
<xp:this.resources>
<xp:script src=”/global/jquery/jquery.js” clientSide=”true”></xp:script>
<xp:script src=”/global/jquery/jquery.mobile.js” clientSide=”true”></xp:script>
<xp:styleSheet href=”/global.jquery.mobile.css”></xp:styleSheet>
</xp:this.resources>

<xp:scriptBlock id=”scriptBlock1″>
<xp:this.value><![CDATA[$(document).on('pageinit', function () {

$.ajax({
url: 'http://dev1//apps/fakenames.nsf/api/data/collections/name/People',
type: 'GET',
async: true,
success: function (result) {
ajax.handleData(result);
},
error: function (request, error) {
alert('Network error has occurred please try again!');
}
});
});

$(document).on('pagebeforeshow', '#headline', function () {
$('#movie-data').empty();

$.each(movieInfo.result, function (i, row) {
if (row["@position"] == movieInfo.id) {
$(‘#movie-data’).append(‘<li><img src=”https://greenhouse.lotus.com/plugins/plugincatalog.nsf/NoPhotoPerson.gif”></li>&#8217;);
$(‘#movie-data’).append(‘<li>Name: ‘ + row.$17 + ‘</li>’);
$(‘#movie-data’).append(‘<li>Company’ + row.CompanyName + ‘</li>’);
$(‘#movie-data’).append(‘<li>UNID : ‘ + row["@unid"] + ‘</li>’);
$(‘#movie-data’).listview(‘refresh’);
}

});
});

var movieInfo = {
id: null,
result: null
}

$(document).on(‘vclick’, ‘#movie-list li a’, function () {
movieInfo.id = $(this).attr(‘data-id’);
$.mobile.changePage(“#headline”, {
transition: “slide”,
changeHash: false
});
});

var ajax = {
handleData: function (result) {
movieInfo.result = result;
$.each(result, function (i, row) {
$(‘#movie-list’).append(‘<li><a href=”” data-id=”‘ + result[i]["@position"] + ‘”><img class=”yourProductSprite yourProductSprite-NoPhotoPerson32″ + src=”https://greenhouse.lotus.com/plugins/plugincatalog.nsf/NoPhotoPerson.gif”/><h3>&#8217; + result[i].$16 + ‘</h3><p>’ + result[i].CompanyName + ‘ / ‘ + result[i].$12 + ‘</p></a></li>’);
});
$(‘#movie-list’).listview(‘refresh’);
}
}]]></xp:this.value>
</xp:scriptBlock>

<div data-role=”page” id=”home”>
<div data-theme=”a” data-role=”header”>
<h3>
Pretenders Directory
</h3>
</div>
<div data-role=”content”>
<div class=”example-wrapper” >
<ul data-role=”listview” id=”movie-list” data-theme=”a”>

</ul>
</div>
</div>
<div data-theme=”a” data-role=”footer”>
<h1>Fake Names – Codestore</h1>
</div>
</div><!– /page –>

<div data-role=”page” id=”headline”>
<div data-theme=”a” data-role=”header”>
<a href=”#home” class=”ui-btn-left” data-transition=”slide” data-direction=”reverse”>Back</a>
<h3>Person details</h3>
</div>
<div data-role=”content”>
<ul data-role=”listview” id=”movie-data” data-theme=”a”></ul>
</div>
</div><!– /details –>
</xp:view>

Tagged with: ,
Posted in jQuery, Mobile

Updated Single Page Application Wizard walk-through

I have updated the walk through of the Single Page Application Wizard available in the Extension Library. You can find the document here. The document covers release 901v00_06.20140424-0600 which contains some improvements for the control e.g.:

  • Improved warnings were created to alert the user to missing or badly configured options.
  • Better defaults were created for certain Wizard options.
  • The Document Viewer label position was changed to “above.”

The default CRUD options are a big time saver, also the checkboxes for fields to display on a Document Viewer Page.

Tagged with:
Posted in Extension Library, Mobile, OpenNTF

#oldschool @formula to check for attachments

I have started at a new company and they didn’t have an XIC (XPages Information Center) so my XPages Knowledge db needed to be installed (a regular Notes db for quickly copying & pasting rich text, snippets, storing sample applications, multiple media files).

The database is a couple of years old so it needed some updates. One was to hide a “files section” from printing in case there are no files attached. I noticed embedded images start with an “ST” naming in the @attachments array (correct me if I am wrong).

Finally I came up with the following rule for a computed sub form:

files:=@AttachmentNames;
counter:=0;
REM{“check if files contains a point. embedded images do not contain them”};
@For(n := 1;n <= @Elements(files); n := n+1;
@If(
@Contains(files[n];”.”);
counter:=counter+1;
“”)
);
@If(@IsNewDoc;”Attachments”;counter!=0;”Attachments”;””)

Tagged with: ,
Posted in @Formula

Engage – signed up

Funny, but a motive when moving to Sweden was to combine work with a bit of holiday. Recently I signed up for the Engage event and will do it the other way around in the Netherlands: combine holiday with a bit of work.

I am looking forward to the event because of it’s great line-up. I am curious how the ‘collaboration market’ nowadays looks like in the Netherlands and Belgium and what the opportunities are.

 

Tagged with: ,
Posted in Education

Single Page Application tutorial

After watching the video on YouTube on the Single Page Application wizard I became curious and decided to take a test and mobilize an application myself. I choose the infamous “fake names” application for this.

I have written a blog article/tutorial about it. Here you can read it: ‘Single Page Application Wizard‘.

Summary

With the Single Page Application control you can rapidly mobilize a Notes application. The wizard is intuitive although you need to understand some basics of mobile development.

Unfortunately the wizard is not complete and forces you to apply some coding.

Infinite Scroll

The infiniteScroll property for a Data View control is enabled by default in the Singe Page Application. This great new feature allows users to fetch new rows of data by scrolling down the list.

You are almost stupid if you disable this feature.

Recommendations

  • Ability to apply basic CRUD Tab Bar Buttons to a Document Viewer Application Page.
  • On a Document Viewer page it would be easier to add fields instead of removing most of all the fields that would otherwise be applied by default. In mobile apps the number of fields you want to display is probably less than in a Notes client application.
  • Ability to re-open the wizard after you have pressed ‘Finish’.
  • It would be great to have message popups when a user performs an action that he/she is not allowed to do. At the current stage there is default no mechanism for this. Examples: “You are not authorized to perform this action”, “You have insufficient access rights”.

m_mobile

m_people

m_person

Tagged with: , , , ,
Posted in Mobile
Introduction
I am Patrick Kwinten. I am a IBM Notes Domino Product Specialist since 1996. With this blog I am trying to give my contribution to the community.
.
OpenNTF
Follow my projects on OpenNTF. Below are some examples:

Categories
RSS Feed
Follow

Get every new post delivered to your Inbox.

Join 201 other followers