Notes on Mobile
Back on track

Hairshirt or not…. the experiment rolls forward!

Now that I got the JSON bug solved worked around I can get back to fleshing out the non-XPages version of the Customers On the GO! app.

The next page is the contact details. The XPages version of this page wasn’t too complicated and I wouldn’t normally dedicate an entire post about it, but this will give me a chance to walk through my Notes document as JSON function I talked about yesterday.

After clicking the ‘Contacts’ link at the bottom of the app, you are sent to the ‘contactsList.html’ page. The page itself is almost identical to the app’s home screen. The content for the page is collected using the JSON formatted output of a view in the CRM applciation using the following JS:

function loadContactsPageData(){
	var cat = getURLParameter("c");
	var parentId = ('00000000'+getURLParameter("documentId")).slice(-8);
	// Get the list data.
	
    $.getJSON('http://10.1.1.39/unplugged/tdtool.nsf/dataProxy?OpenAgent&db=unplugged/rm.nsf&v=JSONContacts&RestrictToCategory='+cat,
        
    	function(data) {
    		var contactArray = convertViewEntryToJSONObject(data);
    		$('#contactDetailsTemplate')                  // Select the template. 
    			.tmpl(contactArray)              // Bind it to the data. 
    			.appendTo('#contactsContainer');   // Render the output.
    		
    		$('#contactsContainer').listview('refresh');
       }
   );
}

The contact template is very basic as well and looks like this:

	<script id="contactDetailsTemplate" type="text/x-jquery-tmpl">
		<li>
		<a href="contact.html?openfileresource&documentId=${noteid}">
		{{if fpjrFunction_WB=="Developer"}}
		<img style="jobImage" src='designer.png'>
		{{else}}
		<img style="jobImage" src='admin.png'>
		{{/if}}
		<span style='contactName'>${fpnhName_WB}</span>
    	<br/><span style='contactDetails'>${fpjrPosition_WB}</span>
    	<br/><span style='contactDetails'>${fppbPhone_WB}</span>
		{{if fppbXtn_WB}}
    	<span style='contactDetails'>  Ext: ${fppbXtn_WB}</span>
		{{/if}}
		</a>
		</li>
	</script>

Not that complicated, and very similar to the first page, so it was really easy to throw together. 

Each item in the above list has a link that brings you to the ‘contact.html’ page where the individual contacts information is displayed. In the XPages version, there was nothing much to this page, and really didn’t offer any more information than the list did. Just the customers name, job role, phone number, and a big button called ‘Call’. So here is where the dataProxy agent comes into play. To get a document all I need is the following URL:
  unplugged/tdtool.nsf/dataProxy?OpenAgent&db=unplugged/crm.nsf/&outputformat=JSON&documentId=00000000

(Of course I would use the real note id, but this is an example). This URL I can use in my JQuery.getJSON call in the same way I was using it with the views.

NotesDocument.js

To make it easier to deal with the document object I create a few helper functions/objects. First was a little JS function to wrap the getJSON call for documents:

function getNotesDocument( db, docid, callback ){
	var url = 'http://10.1.1.39/unplugged/tdtool.nsf/dataProxy?OpenAgent';
	url += "&db=" + db;
	url += "&documentId=" + docid;
	url += "&outputformat=JSON";
    $.getJSON(url,function(data){
    	var doc = new NotesDocument(data);
    	callback(doc);
    });
}

This function takes 3 parameters, the db and docid as strings and the callback that the getJSON function should call. The passed in callback will be called with a NotesDocument object though instead of the direct results from the getJSON call itself. 

The NotesDocument object is simple and only has two functions, a constructor and a method called getItem. This is what it looks like:

var NotesDocument = function(val){
	this.JSON = val.document;
	this.items = {};
	// convert the array of items to named properties in this object
	// this will make accessing them a bit faster than looping through
	// the entire list looking for the item by name
	for( var i = 0; i< this.JSON.item.length; i++ ){
		for( val in this.JSON.item[i] ){
			if( val !== "name"){
				// values get put into a field named the same as their data type
				this.items[this.JSON.item[i].name] = this.JSON.item[i][val];
			}
		}
	}
	delete this.JSON.item; // no need to store the items twice
};

NotesDocument.prototype.getItem = function(item){
	if( this.items.hasOwnProperty(item) ){
		return this.items[item];
	}
	return "";
}

This little bit of code lets me access the item names in much the same way as if I was working directly with the built in NotesDocument object in Domino.

Finally the function that gets the document can be reduced down to this bit of JS:

function loadContactPage(){
		
	var cat = ('00000000'+getURLParameter("documentId")).slice(-8);
	// Get the list data.
	getNotesDocument( "unplugged/crm.nsf", getURLParameter("documentId"), 
		function(doc) {
			$('#contactTemplate')                  // Select the template. 
				.tmpl(doc)              // Bind it to the data. 
				.appendTo('#contactDetails');   // Render the output.
			
			// need to re-apply styles so the 'call' button will
			// be shown normally. For some reason the only way to 
			// get this to work with the link button is to 
			// 'refresh' the entire page.
			$('#contactDetail').trigger('create');
		}
	);
}

One of my biggest frustrations with JQuery Mobile is that it doesn’t deal with dynamic content very well. You probably noticed that there is a call to the ‘trigger()’ function above. After much trial and error, and google searching, it was the only way I could get the ‘Call’ button to render as a JQM Button widget and not a link. The reason all this is needed is that JQM loads a page and does all it’s markup tweaking before the getJSON() call returns. As a result, by the time the template code has been processed, JQM thinks it’s done with the page. To get around it you either need to add all the JQM classes and styles to the template code manually, or you need to force JQM to reprocess the page - which is what calling trigger(‘create’) does when you specify the DIV for the page.

And just like the rest of the pages, I add a event handler to call this function when the contactDetails page is loaded:

$(document).bind("mobileinit", function(){
    [...snip...]
	$('#contactDetail').live('pagebeforeshow',function(event, ui){
		loadContactPage();	
	});
    [...snip...]
}

With the Javascript ready to go all that is left is the page template that will display the data from the document. For that I’m going to use the getItem function in the NotesDocument object directly in my page template:

	<script id="contactTemplate" type="text/x-jquery-tmpl">
		<span class='contactName'>${$data.getItem("fpnhName_WB")}</span><br/>
	    <span class='contactDetails'>${$data.getItem("fpjrPosition_WB")}</span><br/>
		<span class='contactDetails'>${$data.getItem("fppbPhone_WB")}</span>
		{{if $data.getItem("fppbXtn_WB")}}
	    <span class='contactDetails'>  Ext: ${$data.getItem("fppbXtn_WB")}</span>
		{{/if}}
		<a id='callButton' href="tel:${$data.getItem("fppbPhone_WB")}" data-icon="grid" data-role="button">Call</a>
	</script>

When the JQuery template code evaluates the template, you can access some of the objects it passes in directly. The object here we are using is the $data object, which corresponds to the data that you passed to the jQuery.tmpl() function. With that ability we can call the getItem() function and get the value out of the field.

I’m feeling pretty happy with what I have up to this point. The dataProxy agent and the JSON document output is working well, and I’ve been able to keep the look and feel of the app intact.

Next up is the license page.

  1. notesonmobile posted this
Blog comments powered by Disqus