In the previous post, I covered displaying a document from a CouchDB database in the context of a jQuery Mobile page. A difference between local vs external jQuery Mobile pages was discussed, and it was concluded that external pages was beneficial for the client-side application. In finding this happy medium, I also talked about show functions in CouchDB and how they serve up documents upon request.
In this article, I am going to cover another aspect of delivering HTML content from CouchDB – templates. While doing so, I will modify the current document views to provide a cleaner solution (imo) for delivering and rendering document-based jQuery Mobile pages. Hopefully, this will set the basis for creating additional views for the application…
Templates
In the previous post, I covered using show functions to deliver HTML content as a jQuery Mobile page from a CouchDB instance. From the previous show function example for the Albums application, I basically constructed a string that would be interpreted as HTML mark-up using the values from the document. While this is a perfectly valid solution, its probably not the best if we want to reuse parts of that HTML or if the mark-up gets a little too unwieldy for string manipulation based on the request. To provide a little sanity as we start making more page documents for the application, we going to start using templates to stub out the mark-up of an HTML document and fill content dynamically from the show functions.
mustache.js
If you have been following along in the tutorials, you may remember that in the loader.js script there were a few JavaScript files being loaded that were not being referenced within the current application. One of those was mustache.js. I didn’t talk about it at the time and I said we could probably get rid of it for now, but might as well leave it in… hopefully you left it in. If not, you’re screwed. Kidding
I don’t want to go into a mustache explanation as there are already some great articles out there – especially this one from CouchOne – but I will say that mustache.js is a templating engine for rendering any type of content. For our purposes, we are going to use the to_html() function of Mustache to marry our dynamic album document values with an HTML template and deliver pages from our respective show functions from the CouchDB database.
Album Page Template
Our previous version of album.js from the /show directory of our Albums couchapp looked like the following:
/show/album.js
function(doc, req) {
var html = "<div data-role=\"page\" id=\"albumview\">" +
"<div data-role=\"header\" id=\"albumheader\">" +
"<h2 class=\"albumtitle\">" + doc.title + "<\/h2>" +
"<\/div>" +
"<div data-role=\"content\" id=\"albumcontent\">" +
"<h2 class=\"artist\">" + doc.artist + "<\/h2>" +
"<p class=\"title\">" + doc.title + "<\/p>" +
"<p class=\"description\">" + doc.description + "<\/p>" +
"<\/div>" +
"<div data-role=\"footer\" \/>" +
"<\/div>";
return html;
}
That served our purpose at the time, but such string manipulation for each page we are going to serve up makes my eyes bleed
As such, we will use mustache.js to populate document values in an HTML template. First order of business: Remove that string construct from /shows/album.js and put it into a template, replacing the values with {{mustache}} directives.
Create a new directory called templates in your couchapp directory for the Albums application (for me that is at /Documents/workspace/custardbelly/couchdb/albums). Create a new HTML document in your favorite text editor and save the following as album.html in the /templates directory:
/templates/album.html
<div data-role="page" id="albumview" data-position="inline" data-back="true">
<div data-role="header" id="albumheader">
<h1 class="albumtitle">{{title}}</h1>
<a href="#home" data-icon="grid" class="ui-btn-right">Home</a>
</div>
<div data-role="content" id="albumcontent" data-identity="{{document}}">
<h2 class="artist">{{artist}}</h2>
<p class="title">{{title}}</p>
<p class="description">{{description}}</p>
</div>
<div data-role="footer" />
</div>
Essentially, we have just moved our mark-up from one document to another; the difference being that we are now employing {{mustache}}s as placeholders for dynamic content values. You may notice that the names used in the mustaches are just the property names of the document – similar to the previous albums.js example. In fact there are the property names of the object that will be passed to the Mustache engine to generate our page.
Some added jQuery Mobile element content has been added to the new album page document, as well. We added the data-position and data-back attributes to the page div in order to preserve the back button and add a Home page button to the header. This will allow us to always be able to get back to the index.html Home page from an album page.
<a href="#home" data-icon="grid" class="ui-btn-right">Home</a>
We will need to modify the page div in index.html to have an id value of “home”, but setting that hash as the href for the Home button in the header of our album page will, essentially, enable that link to direct the user back to the page content of the parenting document -index.html.
In album.html we have also declared a data-identity for the content div and provided a {{document}} value. This will be the document._id from the album.js show function and we will later see how it will be used. Back to our album.js document…
Album Page Show Function
Open up the /show/album.js document in your favorite text editor and make replace the current content with the following:
/show/album.js
function(doc, req) {
var Mustache = require("vendor/couchapp/lib/mustache");
var stash = {
artist: doc.artist,
title : doc.title,
description: doc.description,
document: doc._id
};
return Mustache.to_html(this.templates.album, stash);
}
As mentioned previously, CouchApp includes the Mustache JavaScript file automatically when generating a new couchapp application. In this example we first assign a reference to the Mustache module through a require() call for the file in the vendor/couchapp/lib directory. A generic stash object is created to assign property values that are dynamically populated into the album.html template (previous snippet) using the Mustache:to_html method.
I am not entirely clear on how it is possible to reference files and directories with the this keyword in a show function, but i can only assume that couchapp has generated an object tree based on the file structure from which one can access values. If you do know, please leave a comment. In any event, the template file and the defining object are the first two arguments for Mustache:to_html. Upon request for an album document, this will return the album.html page dynamically populated with the values for the document related to the id in the request URL (eg. http://127.0.0.1:5984/albums/_design/albums/index.html#_show
/album/db04eb7e5c845ee0aa791ae1ed000fe8).
Hiccup
There may be a slight problem in this solution however…. Though CouchDB does request-cacheing based on header ETags on documents, jQuery Mobile also does cacheing of pages (or rather it accesses ‘pages’ already loaded into the DOM). So there may be a time that an album has been edited during the application session and jQuery Mobile serves up old information as it never went back out the make a GET request to CouchDB, utilizing this show function. We could make a request for the document each time the page is shown in the DOM using the jquery.couch library, but that may be unnecessary overhead; not to mention a waste of the templating engine.
Another solution, and one I think is viable and worth consideration, is to remove the page from the jquery Mobile page cache when this page is hidden in the view (when you navigate to another page). In order to do so, we will need to access the cached page in the DOM using JavaScript. Instead of adding this JavaScript directly in the HTML template file, we will use another templating feature available in Mustache – Partials.
Partials
Partials are, essentially, just a way to include common mark-up or code or what have you into the target template page. It’s important to remember that partials are rendered in first so any {{mustache}}s in the partial file will also be filled. For the purposes of our example application, we are just going to include mark-up to load a script. It may be a little overkill at the moment, but I wanted to show the use of partials as they can be very handy.
Open up your favorite text editor and save the following snippet as scripts.html in /templates/partials/album.
/templates/partials/album/scripts.html
<script src="../../script/album-page.js"></script>
[02-06-2010: Thank you to Steve and Stacy Braxton for leaving a comment noting that the filepath to scripts.html for the album page was incorrectly shown in italics. The correct filepath is now displayed. Thanks!]
Real boring stuff and not using the full breath of what Partials can do. Basically we are just loading in an associated JavaScript file with our page from the show function. Great. Now we have to create another file. I know, I know. It may appear convoluted, but in my head it is much cleaner and organized. The script we are about to create, could be included in this partial or in the template, but i prefer to work with another separate JavaScript file whose purpose I know based on its extension – its got script in it.
album-page.js
You may have looked at the path in the src attribute value from the Partial we just created and noticed that it is a relative path that goes out a couple directories. That is going back to the _attachments directory to access the album-page.js file from the script folder. The _attachments directory also houses the style folder in which we added the jQuery Mobile styles in the first post.
We’re going to create an add the album-page.js file to the /_attachments/script directory and it will provide the ability to access and clear the page from the page cache of jQuery Mobile so as to always serve up a the page from CouchDB (based on its own cacheing mechanism) using the show function. Open up your favorite text editor and save the following snippet as album-page.js in /_attachments/script:
/_attachments/script/album-page.js
var AlbumPageController = function() {
function handleView()
{
// Watch for bound hide of page to clear from cache.
var docId = $("#albumcontent").data("identity");
var albumPage = $(document.getElementById("_show/album/" + docId));
albumPage.bind( "pagehide", handlePageViewHide );
}
function handlePageViewHide()
{
var docId = $("#albumcontent").data("identity");
var albumPageCache = $(document.getElementById("_show/album/" + docId));
albumPageCache.unbind( "pagehide", handlePageViewHide );
albumPageCache.empty();
albumPageCache.remove();
}
return {
initialize : function() {
$("div[data-role='page']").live( "pageshow", function() {
$("div[data-role='page']").die( "pageshow" );
handleView();
});
}
};
}();
function handlePageViewReady()
{
AlbumPageController.initialize();
}
$().ready( handlePageViewReady );
In essence, we are just creating a view controller for our jQuery Mobile page served up from the show function. Once the page is recognized as part of the DOM, the controller is initialized and an event handler is assigned to the pageshow event for the current page – the album.html served up. We access the page in the DOM using the standard data-role attribute value for a jQuery Mobile page. I stumbled upon this solution from these two forum posts – http://forum.jquery.com/topic/force-page-update and http://forum.jquery.com/topic/binding-events-to-buttons-in-a-dialog – and seem to be the current agreed upon solution for accessing a loading jQuery Mobile page.
Now, it should be noted that setting that handler will actually set a handler on all divs with the data-role attributed as “page”. But since we are only concerned with the pageshow event, we know that the current target is the album page. Once that event is captured, we remove the handler and assign a pagehide event handler to clear the page from the jQuery Mobile (ie. DOM) cache and remove the elements from the DOM.
Since the album page is an external page (defined in the script in index.html when building the list items), its registered in the DOM and accessed using the _show path based on the document ID. So, when the page is fully loaded we access that page recognized in the DOM using the getElementById() method:
var docId = $("#albumcontent").data("identity");
var albumPage = $(document.getElementById("_show/album/" + docId));
Accessing the page as such, we can empty all its elements and remove it once the page has been fully hidden from the view in the page transition of jQuery Mobile:
var docId = $("#albumcontent").data("identity");
var albumPageCache = $(document.getElementById("_show/album/" + docId));
albumPageCache.unbind( "pagehide", handlePageViewHide );
albumPageCache.empty();
albumPageCache.remove();
That essentially will make a request each time to CouchDB for the album document page and not rely on the cacheing of pages within jQuery Mobile. This will also open up the ability to assign and manage handlers for other events, such a requesting pages for editing a document… but we’ll broach that subject in another post
For now, let’s go back and update our album.js and album.html documents to include the partial.
[01-28-2010: Thank you to IR for leaving a comment alerting me to the fact that i totally missed out on updating the neccessary files after creating the partial]
Modifying album.js and album.html
Open up /shows/album.js in your favorite text editor and make the following modification to pass the partial directory in Mustache.to_html():
/shows/album.js
function(doc, req) {
var Mustache = require("vendor/couchapp/lib/mustache");
var stash = {
artist: doc.artist,
title : doc.title,
description: doc.description,
document: doc._id
};
return Mustache.to_html(this.templates.album, stash, this.templates.partials.album);
}
That last argument in to_html() will allow you to stub out the documents included in the /album folder of the partials directory in the album.html template. We’ll need to update that document as well for our scripts partial to be included.
Open up /templates/album.html and make the following modification:
/templates/album.html
<div data-role="page" id="albumview" data-position="inline" data-back="true">
<div data-role="header" id="albumheader">
<h1 class="albumtitle">{{title}}</h1>
<a href="#home" data-icon="grid" class="ui-btn-right">Home</a>
</div>
<div data-role="content" id="albumcontent" data-identity="{{document}}">
<h2 class="artist">{{artist}}</h2>
<p class="title">{{title}}</p>
<p class="description">{{description}}</p>
</div>
<div data-role="footer" />
</div>
{{>scripts}}
A slight modification to the syntax on how you would include object property values, the partial is included by appending the name of the partial document to include with a greater than character. That will essentially write the content of the document inline in the template where it is declared.
Now we just need to make a small modification to the index.html file and then deploy our modified application to the CouchDB instance so we can view our wonderful changes (which won’t look like we changed a thing).
Modifying index.html
We added a Home button to the header bar of the album page so we could always navigate back to the Home page. Currently the album page is accessible from the album list on the Home page, but who knows, maybe that won’t always be the case in the future. In any event, we made the change and assigned the href value for the Home page button with the #home anchor. Currently that will go nowhere. We’ll set that as the div id on the main jQuery Mobile page in index.html.
Open up the /_attachments/index.html file in your favorite text editor and make the following modifications the #home page div:
/_attachments/index.html
<div id="home" data-role="page">
<div data-role="header"><h1>Albums</h1></div>
<div data-role="content">
<ul id="albums" data-role="listview" data-theme="c" data-dividertheme="b"></ul>
</div>
<div data-role="footer" class="ui-bar"><h4>a list of albums</h4></div>
</div>
[02-05-2010: Thank you to Otetz for leaving a comment about the missing call to refresh the list prior to shoe on the index.html file]
With index.html still open in your favorite text editor, add the following line to the handleDocumentReady() method in the inline JavaScript:
function handleDocumentReady()
{
$("#home").bind( "pagebeforeshow", refreshAlbums );
refreshAlbums();
Save that, and now we can add a Home button to any page and will always be directed back to that div with the list of albums from our CouchDB database. Cool. Time to deploy.
Deployment
We modified our show function to use templates and created a script to empty the page and its elements from the DOM upon hide within the jQuery Mobile context and are assured that each access of an album document will contain the latest changes. With these modifications saved, we can now push to the CouchDB database using the couchapp utility. Open a terminal and navigate to the directory where you create your CouchApp applications (for me that is /Documents/workspace/custardbelly/couchdb and in there i have a folder named albums which is the CouchApp application directory for these examples). Enter the following command to push the changes to the CouchDB instance:
couchapp push albums http://127.0.0.1:5984/albums
If all was successful and you now go to http://127.0.0.1:5984/albums/_design/albums/index.html, we’ll still have our old familiar list and still access each album by clicking on a list item. Basically it performs exactly as it had before, but we cleaned up a little on our end… a benefit to us as the developer and a benefit to the user though not visually noticeable… it still looks rather ugly
Conclusion
We delved a little deeper into how to serve up pages from CouchDB using templates and partials (thanks to Mustache!) and also touched on accessing pages from DOM cache in the context of jQuery Mobile framework. All nice stuff, but nothing really has changed in how the application worked for the end user. We ensured that album pages always had the correct and latest content, but we haven’t opened up the possibility to edit the document and commit changes. That’s to come
Just wanted to lay the groundwork for easing into adding more pages to our application. Hopefully you found some of this useful.
[Note] This post was written against the following software versions:
CouchDB – 1.0.1
CouchApp – 0.7.2
jQuery – 1.4.4
jQuery Mobile – 1.0a2
If you have found this post and any piece has moved forward, hopefully the examples are still viable/useful. I will not be updating the examples in this post in parellel with updates to any of the previously mentioned software, unless explicitly noted.
Articles in this series:



Thank you for sharing. I found an error caused by the missing statement for the mustache partial in /shows/album.js
i change the line
return Mustache.to_html(this.templates.album, stash);
to
return Mustache.to_html(this.templates.album, stash, this.templates.partials.album);
thats it
Nice catch IR! I totally forgot to explain how to include the partial. The post has been updated.
Thanks again,
-todd
Hi
Nice tutorial. Thanks a lot.
I hade a problem getting the code to work, until I made the following change:
In /templates/album.html, line 1, I rename id=”albumview” into id=”album”.
For full working partial also need to add this line
$(”#home”).bind( “pagebeforeshow”, refreshAlbums );
into handleDocumentReady() in index.html
@Otetz you are right. totally missed adding the update to refresh on return to #home in the examples. The post has been updated. Thanks for catching that!
-todd
This is a really great series of posts. My first real experience with jQuery Mobile.
I think I may have found a minor typo in the “Templates and Mustache” post where partials are introduced. The path for the file to create is “/templates/partials/albums/scripts.html”, but later it is referred to in album.js using “this.templates.partials.album”. Changing the directory name in the earlier step to “/templates/partials/album” gets everything working again.
Keep up the great work I can’t wait to read part 7, whichever topic you choose (my preference would be authentication).
Thanks again,
Steve
Thank you SO much for this tutorial. One wee bitty catch: The italicized caption for where to save the partial says “/templates/partials/albums/scripts.html” (”albums” plural) but everywhere else the directory is “album” (singular).
Again, thank you for posting this! I have been trying to work through the Sofa tutorial in the free CouchDB online book but they never updated the book to explain Mustache (to which the tutorial code has been adapted).
Thanks so much Steve and Stacy Braxton for catching that type-o! The post has been updated. I hope you are still enjoying the series. Cheers!
Thanks. I’ve learned many things with your tuto.
I’ve found issues with AlbumPageController.
I’m using jquery 1.5.2 and mobile 1.0a4.1.
I fixed it with this simplier solution.
var AlbumPageController = function() {
function handleView(cur_page) {
// Watch for bound hide of page to clear from cache.
var albumContent = $("#albumcontent", cur_page);
var albumPage = albumContent.closest('div[data-role=page]');
albumPage.bind( "pagehide", handlePageViewHide );
}
function handlePageViewHide() {
//this is div[data-role='page'] to hide
$(this).unbind( "pagehide", handlePageViewHide )
.empty()
.remove();
}
return {
initialize : function() {
$("div[data-role='page']").live( "pageshow", function() {
$("div[data-role='page']").die( "pageshow" );
//this is div[data-role='page'] to show
handleView(this);
});
}
};
}();
function handlePageViewReady() {
AlbumPageController.initialize();
}
$().ready( handlePageViewReady );
Don’t know if it’s working with your jquery mobile version.
ah, nice paz. Yeah i had created this couchapp using jQuery 1.4.4 and the alpha 2 of jQM. There were some hacks that needed to be done back then and jQM has certainly grown up a bit since then (As have i
).
This is a nice way to handle the scope access of the page. Thanks
I’ve found a strange problem. CouchDB on Windows platform works with your tutorial but if I use Linux as platform, I need to add a “../../” in front of the path in /templates/partials/album/scripts.html in the line ”. so it looks like ”. otherwise I see in firebug, that the script file is not found.
Can you explain me, what’s wrong on Linux?
@Michael
Hmm. That is interesting. I am not sure the problem or if i can help. I have CouchDB running on an Ubuntu slice which i eventually pushed the example application to and did not have to update the paths.
I am not much of a Linux user, however. Hopefully someone can find an answer for you in these comments. I am sorry i couldn’t be of more help.
some small typos:
album page show function: the directory must be shows (not show) – as later correctly stated.
modifying index.html (at end) : at the end of the code snipet a closing } is missing.
working with couchapp 2.0 i had also problems with the
{{>scripts}} include in album.html. i think they way couchapp handles mustaches etc. has changed (see the tutorial for evenly at http://couchapp.org/page/evently-do-it-yourself , which gives a more streamlined solution).
This is a great tutorial.. I have a question, and I’m not sure where to ask. I’m writing a show function to create a futon-like interface to edit a document. Some fields will be locked (like the _id and Name), other fields will be editable, and new fields may be added to the document.
Thus, for any given document, I have a variable number of fields and field names. How do I iterate over the fields and render both the names of the keys as well as their respective values in a show?
Thanks and keep up the good work.
hi,
I don’t think this makes any sense. Please stop writing articles when you have no knowledge, you shit bag. Never writ e such lengthy articles.
teri ma ki aankh
Vaibhav,
I am sorry you feel that way.
This article is quite old and was written using technologies and libraries that are now out of date. I do not plan to update these articles with the latest of CouchDB or JQuery Mobile as in the past year and a half since the articles on this site were written, there are a plethora of more updated articles on the subject and the platform available on the internet.
Hi Todd,
Sad to see a negative comment. I’m finding the tutorial very helpful! Thanks for posting this. One q: you wrote this almost 2 years ago. I’m a noob to front end development. JQuery Mobile and CouchDB are new to me. Are these tools still popular/heavily used/being updated? I noticed when trying to get CouchDB running on my machine that some of the tutorials are outdated.
Thanks!
Hi John,
jQuery Mobile is still very much active and has gained a lot of support from the community and popularity amongst developers. Some of the work-arounds described in this tutorial may now be obsolete as the library matured and added support. So some pieces of code may have you wondering why I didn’t do X or Y; the reason being that it wasn’t in the library at the time.
CouchDB and couchapp are still active as well, but I am not so familiar with their current state and support on platforms. I have not work with either for possibly a year. That is not to say that they are not valid technologies, just have not had the pleasure of being in a position to offer them as a solution in my current work.
Todd, think I found a really slick update that gets around the page cache issue. There’s a new data-cache page attribute that you can set to “false”. See this jqm blog post update – http://jquerymobile.com/blog/2011/05/06/jquery-mobile-team-update-week-of-may-2/