Table of Contents

CouchDB’s forms make writing applications easy. They are inspired by a similar feature in Lotus Notes. A CouchDB form is a function which receives a JSON document as it’s argument, and may return an HTTP response with any Content-Type. The form we’re building today displays a blog post as an HTML page, which includes links to stylesheets and other assets, which we’ve stored as attachments to the application’s design doc.

Hey, this is great, we’ve rendered a blog post!

[Screenshot -- blog page with post]

The complete form function and template will render a static, cacheable resource, that does not depend on details about the current user, or anything else aside from the requested document and Content-Type. Generating HTML from a form function can not cause any side effects in the database, which has positive implications for building simple scalable applications.

Rendering Documents With Show Functions

function(doc, req) {
  // !json templates.post
  // !json blog
  // !code vendor/couchapp/template.js
  // !code vendor/couchapp/path.js
  // we only show html
  return template(templates.post, {
    title : doc.title,
    blogName : blog.title,
    post : doc.html,
    date : doc.created_at,
    author : doc.author,
    assets : assetPath(),
    editPostPath : showPath('edit', doc._id),
    index : listPath('index','recent-posts',{descending:true, limit:5})
  });
}

The Post Page Template

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %> : <%= blogName %></title>
    <link rel="stylesheet" href="../../screen.css" type="text/css">
  </head>
  <body>
    <div id="header">
      <a id="edit" href="<%= editPostPath %>">Edit this post</a>
      <h2><a href="<%= index %>"><%= blogName %></a></h2>
    </div>
    <div id="content">
      <h1><%= title %></h1>
      <div id="post">
        <span class="date"><%= date %></span>
        <div class="body"><%= post %></div>
      </div>
      <div id="tags"></div>
      <div id="comments">
        <ul></ul>
        <!-- form to create a comment -->
        <form id="new-comment" action="post.html" method="post">
          <h3>Comment on this post</h3>
          <p><label>Name</label>
          <input type="text" name="commenter-name" value=""></p>
          <p><label>Url <em>(optional)</em></label>
          <input type="text" name="commenter-url" value=""></p>
          <p><label>Email <em>(for Gravatar)</em></label>
          <input type="text" name="commenter-email" value=""></p>
          <p><label>Comment <em>(with Markdown)</em></label>
          <textarea name="comment" rows="8" cols="40"></textarea></p>
          <p>
            <input type="button" id="preview" value="Preview">
            <input type="submit" value="Save &rarr;">
          </p>
        </form>
        <div id="comment-preview"></div>
      </div>
    </div>
  </body>
</html>

Dynamic Dates

When running CouchDB behind a caching proxy, this means each form should only have to be rendered once per updated document. However, it also explains why the timestamp looks like 2008/12/25 23:27:17 +0000 instead of "9 days ago".

It also means that for presentation items that depends on the current time, or the identity of the browsing user, we’ll need to use client-side JavaScript to make dynamic changes to the final HTML.

Dynamic Dates
$('.date').each(function() {
  $(this).text(app.prettyDate(this.innerHTML));
});

We include this detail about the browser-side JavaScript implementation, not to teach you about Ajax, but because it epitomizes the kind of thinking that makes sense when you are presenting documents to client applications. CouchDB should provide the most useful format for the document, as request by the client, but when it comes time to integrate information from other queries, or bring the display up-to-date with other web services, by asking the client’s application to do the lifting, you move computing cycles and memory costs from CouchDB to the client. Since there are typically many more clients than CouchDBs, pushing the load back to the clients means each CouchDB can serve more users.

figure/ajax-post-screenshot.png
When the document is successfully loaded and rendered, it will look something like this screenshot.A Rendered Post