Wednesday, February 17, 2010

CouchApp Templates for Showing Documents

‹prev | My Chain | next›

Up tonight is more couchapp fun. Last time around, I was able to install dirt simple pages, including the ability to insert request parameters and document attributes. Tonight I would like to explore the templating feature some with a stretch goal of creating an edit page (updates will come tomorrow).

Templating in couchapp is accomplished via micro-templating from John Resig of jQuery fame. First I need a templates directory (I'm not positive this is needed, but I follow the convention of sofa here):
cstrom@whitefall:~/repos/relax$ mkdir templates
cstrom@whitefall:~/repos/relax$ touch templates/recipe.html
(I am still working in my "relax" couchapp directory from the other day here)

I will populate that template with HTML and other stuff in a bit, but first I create the corresponding show function in the "shows" directory. Specifically, I will create "shows/recipe.js". In that show function, I define the following javascript:
function(doc, req) {
// !json templates.recipe
// !code vendor/couchapp/template.js
return template(templates.recipe, {
title: doc.title
});
}
The !json comment is a couchapp directive, which inserts the templates/recipe.html file into the function at that point and assigns it to a templates.recipe variable/attribute. Similarly, the !code directive inserts code directly from the template.js file into the function. The template.js javascript file contains the micro-templating function template which allows the template() function in the return statement to work.

Now I add HTML to the show function:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Recipe: <%= title %></title>
</head>

<body>
<h1><%= title %></h1>

</body>
</html>
If I have done this correctly (and I my understanding is right), the title of the recipe document (assigned in recipe.js) should be inserted wherever the <%= title %> appears.

I upload the couchapp show function to my recipe database:
cstrom@whitefall:~/repos/relax$ couchapp push http://localhost:5984/eee
[INFO] Visit your CouchApp here:
http://localhost:5984/eee/_design/relax/index.html
I access the show document, applied to a spinach artichoke pie from 2008-07-21 with this URL:http://localhost:5984/eee/_design/relax/_show/recipe/2008-07-21-spinach. The page looks like:



Nice! It worked.

It occurs to me that I have images attached to my recipe documents. To get the image filename, I add the following to the recipe.js code:
function(doc, req) {
// !json templates.recipe
// !code vendor/couchapp/template.js

var image;
for (var prop in doc._attachments) {
image = prop;
}

return template(templates.recipe, {
title: doc.title,
docid: (doc && doc._id),
image: image
});
}
I also added the docid calculation above because it will be needed in the html template:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Recipe: <%= title %></title>
</head>

<body>
<h1><%= title %></h1>

<img src="../../../../<%= docid %>/<%= image %>" />

</body>
</html>
There is probably a better way to get the path (it needs to be relative to the database) than that, but I will figure that out another day. For now, I push the couchapp, reload the web page and:


Nice!

I am not going to reach my stretch goal of starting on the edit template, but before I stop for the day, I do want to make sure I know how to do stylesheets. The generator for couchapp created _attachments/style/main.css. I add the following for the H1 tag:
h1 { border: 2px dotted orange; }
(It should be pretty obvious if that is working!)

Another couchapp supplied javascript file comes in handy here-vendor/couchapp/path.js contains various functions that can generate URL paths (maybe one of them will help my dot infested image tag). The function that I need for stylesheets is assetPath():
function(doc, req) {
// !json templates.recipe
// !code vendor/couchapp/template.js
// !code vendor/couchapp/path.js

var image;
for (var prop in doc._attachments) {
image = prop;
}
return template(templates.recipe, {
title: doc.title,
docid: (doc && doc._id),
asset_path: assetPath(),
image: image
});
}
Using the asset_path local variable in the template looks like:
<link rel="stylesheet" href="<%= asset_path %>/style/main.css" type="text/css" />
After a final re-push of my couchapp design document, I find:



Yup! Ugly orange dots. That is a fine stopping point for tonight. I may do a bit more work on the show before moving onto to the edit. Tomorrow.

Day #17

2 comments:

  1. I too have been playing around with couchapp. I'm currently trying to work out in my head how to DRY up template rendering for a site with a lot of screens, and after that, the feasibility/implications of offloading complex server-side work to CouchDB's External Processes.

    Anyways, I've started following your blog recently, so I wanted to introduce myself and say 'thank you' for documenting your problems and solutions so thoroughly.

    Cheers,
    Joel (unsigned_char on #couchdb)

    ReplyDelete
  2. I'm curious about DRYing templates up as well. I got header/footer templates here: http://japhr.blogspot.com/2010/02/textile-and-partial-templates-in.html

    That's not quite good enough IMO. A wrapper template_with_layout() method could be used to assemble header, footer, and page content, but you'd still have to declare the !json directives everywhere to pull in the templates. You could put the HTML in another javascript library, but you'd still have to !code it in to each page and who wants to code a bunch of HTML inside Javascript strings?

    I don't foresee any external work that I'd need any time soon (aside from couchdb-lucene). Still I'm definitely interested in understanding it more. I really should hang out in #couchdb sometime... :)

    Glad you're finding this interesting. Thanks for saying hi!

    ReplyDelete