Notes on Mobile
Just the basic details

Like with the XPages version, this page will be pretty simple in it’s overall structure:

<body>
	<div data-role="page"  id="details">
	<div  data-position="fixed" data-role="header">
	<a rel="externa" href="index.html" data-icon="arrow-l" data-iconpos="left">Home</a>
		<h1 id='companyName'></h1>
	</div>	
	<div data-role="content">
	<div id='companyDetails'></div>
	<div id='mapCanvas' style="margin-right:20px;width: 100%; height: 360px;"></div>
	
	<a href="#" data-icon="forward" data-role="button">Directions</a>
	<a href="#" data-icon="grid" data-role="button">Call</a>
	
	</div><!-- /content -->
	<div  data-position="fixed" data-role="footer">
		<div data-role="navbar">
		<ul id='footerNavLinks'>
			<li><a href="#" class="ui-state-persist ui-btn-active">Details</a></li>
			<li><a href="#" onclick="changeCategory('contactList.html')">Contacts</a></li>
			<li><a href="#" onclick="changeCategory('licenseList.html')">Licenses</a></li>
			<li><a href="#" onclick="changeCategory('notesList.html')">Notes</a></li>
		</ul>
		</div><!-- /navbar -->
	</div><!-- /footer -->
</div><!-- /page -->
</body>

In this block of code there are two things to keep an eye on. First is in the header <div>:

<h1 id='companyName'></h1>

Next is the <div> with the id ‘companyDetails’:

<div id='companyDetails'></div>

Also you may have noticed that in the footer, each link contains an onclick handler, but I’ll get to that later.

The two id’s above are going to be where my replacement text ends up. Notice how the replacement target it can be any thing you want, not just a <div>.

Here are the templates I’m going to use:

	<!-- 
		JQM only loads the [data-role='page'] element into the linked pages
		so the templates all need to be here, in that <div> not in the <head>
	-->
	<script id="companyNameTemplate" type="text/x-jquery-tmpl">
		${fcftCompany_WB}
	</script>
	<script id="companyDetailsTemplate" type="text/x-jquery-tmpl">
		<span style="display:none" id="address">${faddLocation_SS}</span>
		<span style="display:none" id="companyName">${fcftCompany_SS}</span>
		<span class='companyAddress'>${faddAddress_SS}</span><br/>
		{{if faddAddress_SS_1.length}}
		<span class='companyAddress'>${faddAddress_SS_1}</span><br/>
		{{/if}}
		<span class='companyAddress'>${faddTown_SS}, ${faddCounty_SS}   ${faddPostcode_SS}, ${faddCountry_SS}</span><br/>
	</script>
	

It is very important that these two <script> blocks go inside the <div data-role=’page’>. The reason, which took me a while to come to realize has to do with the way JQuery Mobile follows links. JQM uses AJAX to load the content of the page pointed to by all <a> tags unless you use the rel=”external” or its variants. This is done so the next page can have fancy transitions. The way a page slides in from the right is an example of this effect. The way it works is that in the background, JQM gets the div from the new page that contains the data-role=’page’ attribute and only loads that into the current page by replacing the current data-role=’page’ div. The effect is neat but it actually can cause really bizarre things to happen if you don’t watch out. For example, in the first page I created, I placed the template blocks in the <head> of my page. In the first version of the details page I did the same thing. After my first test, I couldn’t get the customer name to show up in the title bar and I would be getting ‘object has no method ‘appendTo” errors in the JS Console:

It took a while to figure this out, but the cause was that when JQM loaded details.html page, it only use the data-role=’page’ div. At that point I had two options. The first was to load the template into the <head> of the first page. Since that page is used as the target for the next page to load into, my template will be there. The other option, which I ended up going with, was to put all the things I wanted to load into the page div. I like the second approach because it keeps the ‘page’ more intact. Keeping everything in the first page just seems really messy to me.

The next step is to update the ‘mobileinit’ function in my app.js with the following code for my new details page:

$(document).bind("mobileinit", function(){
	$('#main').live('pageshow',function(event, ui){
		loadMainPageData();
	});
        $('#details').live('pagebeforeshow',function(event, ui){
		loadDetailsPageData();	
		loadMap();		
	});
});

Here is where I hit my first real problem. Getting a list of customers from a view is pretty easy. Getting a single customer document is not. There is no Domino URL parameter to read a document as JSON. This will have to be the first design change I make. I figure I have a couple options though. First option would be to create an agent I can call that returns the document I want in JSON format. The upside to this is the flexibility it would give me as I could add what ever I wanted, and it would make RichText possible. The downside to this is that I would have to be able to run code on the server which means signing the database with the correct Id. I don’t really want to deal with that right now. The second option is to still use a new view and categorize it on the Note ID or customer name of the document I want, and add all the fields I need as columns. This has two distinct advantages - it’s easy to create views and change them without needing special access, and it keeps the native Domino changes to a minimum. Agents require testing and they are not easily ported if I ever want to move the data off of Notes (gasp!! - I’m not in charge of IT so who knows what will happen tomorrow….). So the view I created is really simple. Categorized on NoteID and I added columns for each field I wanted off of the document. I have no RichText in these documents that I need, so this will work fine for now. With the view created I have the following function for loading a customer ‘document’:

function loadDetailsPageData(){
	var cat = ('00000000'+getURLParameter("documentId")).slice(-8);
	// Get the list data.
    $.getJSON('http://10.1.1.39/unplugged/rm.nsf/JSONCustomers?readviewentries&outputformat=json&RestrictToCategory='+cat,
    	function(data) {
	    	var doc=convertViewEntryToJSONObject(data);
	    	$('#companyNameTemplate')                  // Select the template. 
    			.tmpl(doc)              // Bind it to the data. 
    				.appendTo('#companyName');   // Render the output.
    		$('#companyDetailsTemplate')                  // Select the template. 
    			.tmpl(doc)              // Bind it to the data. 
    			.appendTo('#companyDetails');   // Render the output.

      		codeAddress();
       }
   );
}

function convertViewEntryToJSONObject(data){
	var obj = {};
	obj.noteid = data.viewentry[0]["@noteid"];
	for(var i=0;i<data.viewentry[0].entrydata.length;i++){
		obj[data.viewentry[0].entrydata[i]["@name"]]=data.viewentry[0].entrydata[i].text[0];
	}	
	return obj;
}

The document I want is loaded via a URL parameter just like before, and the URL I use is almost the same to get the JSON data. The only difference is that I added ‘RestrictToCategory’ to the url and used the NoteID as the parameter. This data returned by the view JSON is not quite what I want so the function convertViewEntryToJSONObject() takes the normal view JSON

and converts to another object that looks more like a document

Having this faux document object makes it much easier to create and maintain my templates in the html. My template can refer to actual field names just like in the Xpage version, instead of viewentry[0].entrydata[2].text[0]. Much easier to read.

Loading the map and displaying the address happen in exactly the same way, and I was able to use the same functions from earlier to do it. All I did was copy that code from the XPage and put it into the app.js file.

So this is a lot to cover in one post. I know it seems like a lot of code, but everything done today is laying the ground work for all the pages to come, so the rest should be much easier. Next time I’ll finish with this page and take a look at the footer and the links there.

  1. notesonmobile posted this
Blog comments powered by Disqus