Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Update the haml article for latest node.

  • Loading branch information...
commit 564cbe9e40246c75e178a1cd98d30da4087b8ba6 1 parent 6683fe2
@creationix authored
View
150 articles/haml-for-javascript.markdown
@@ -1,20 +1,22 @@
Title: Using HAML templates in JavaScript
Author: Tim Caswell
Date: Sat Feb 06 2010 23:06:39 GMT-0600 (CST)
+Node: v0.1.102
One of my favorite libraries when I was doing [ruby][] development was the HTML templating language [HAML][]. For those of you who haven't yet been enlightened, it's an alternate syntax for XML that results in a **lot** less code to write the same thing.
When I switched to primarily JavaScript, I missed HAML so much I wrote two ports of it. One is called [jquery-haml][]. It's a dom-building library with some really advanced DOM integration tricks. The other is [haml-js][]. It's a text-to-text compiler that translates HAML code to HTML, perfect for node based websites.
+**UPDATE** This article was left as is mostly, current development resides in [jade][] and [grain][].
+
## Using `haml-js` in a node website ##
Using [haml-js][] is pretty straight-forward. First, you install `haml-js` as a library for use in node. The full docs are [here][], but I'll show how I set up my node libraries.
### Installing `haml-js` in node ###
-There isn't really a standard package manager in node, but it's not hard to install a package once you've done it a time or two. I like to use git for all GitHub based libraries so that I can update any library by issuing a pull command.
+There wasn't a standard package manager for node when this was written, but it's not hard to install a package once you've done it a time or two. I like to use git for all GitHub based libraries so that I can update any library by issuing a pull command.
- #!sh
tim@TimBook:~$ mkdir Code
tim@TimBook:~$ cd Code/
tim@TimBook:~/Code$ git clone git://github.com/creationix/haml-js.git
@@ -30,112 +32,57 @@ There isn't really a standard package manager in node, but it's not hard to inst
Basically I made a folder for code clones, another one for node libraries, and linked the two up so node can find the code.
-After you've done this once, you can skip the `mkdir` commands on your next library install.
-
## Checking the install ##
-Open up a `node-repl` session and see if you can import my library.
+To test if it's installed, open a `node` terminal and try to `require` it.
- #!sh
- tim@TimBook:~$ node-repl
- Welcome to the Node.js REPL.
- Enter ECMAScript at the prompt.
+ tim@TimBook:~$ node
+ Type '.help' for options.
node> var Haml = require('haml');
- {
- "compile": [Function],
- "optimize": [Function],
- "render": [Function],
- "execute": [Function]
- }
node> Haml.render('.classy Hello World')
- "<div class=\"classy\">Hello World\n</div>"
+ '<div class="classy">Hello World</div>'
Great, it's working! If this is not working for you, the [node mailing list][] is a really friendly place if you need help getting this setup.
## A simple HAML based site
-As you saw in the last section, you can test it from a `node-repl` session, but let's make a whole program with partials, loops and conditionals just for fun.
+As you saw in the last section, you can test it from a `node` session, but let's make a whole program with partials, loops and conditionals just for fun.
+
+Note that I'm using blocking I/O for these examples to simplify the examples and focus on the haml. If you were to use this code in the request loop of a running server, be sure you converted it to use the non-blocking versions.
### Layout template
First let's make our layout template, we'll save it as `layout.haml`:
- #!haml
- !!! Strict
- %html(lang="en")
- %head
- %title&= title
- %body
- = contents
+<haml-for-javascript/layout.haml>
### Start of Program
Now we'll write a short node program to render it:
- var Haml = require('haml'),
- File = require('file'),
- sys = require('sys');
-
- File.read('layout.haml').addCallback(function (haml) {
- var data = {
- title: "Hello Node",
- contents: "<h1>Hello World</h1>"
- };
- var html = Haml.render(haml, {locals: data});
- sys.puts(html);
- });
+<haml-for-javascript/step1.js>
This program will output:
- #!html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
- <html lang="en"><head><title>Hello Node
- </title></head><body><h1>Hello World</h1>
- </body></html>
+ <html lang="en"><head><title>Hello Node</title></head><body><h1>Hello World</h1></body></html>
### Subpage
Usually you'll want another template for your actual pages and just share the common layout between them. So we'll make an actual page with a little logic in it and save it as `users.haml`.
- #!haml
- %h1 Users
- :if users.length === 0
- %p There are no users in the system.
- :if users.length > 0
- %ul
- :each user in users
- %li&= user
+<haml-for-javascript/users.haml>
There are two branches in this template. If the users list is empty, then a static message will be shown; if not, then each user will be shown as a list item.
Here is how we modify the code to use this page:
- File.read('layout.haml').addCallback(function (layout_haml) {
- File.read('users.haml').addCallback(function (users_haml) {
- var data = {
- users: ["Tim", "Sally", "George", "James"]
- };
- var page_data = {
- title: "System Users",
- contents: Haml.render(users_haml, {locals: data})
- };
- var html = Haml.render(layout_haml, {locals: page_data});
- sys.puts(html);
- });
- });
+<haml-for-javascript/step2.js>
And here is the output:
- #!html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
- <html lang="en"><head><title>System Users
- </title></head><body><h1>Users
- </h1><ul><li>Tim
- </li><li>Sally
- </li><li>George
- </li><li>James
- </li></ul>
- </body></html>
+ <html lang="en"><head><title>System Users</title></head><body><h1>Users</h1><ul><li>Tim</li><li>Sally</li><li>George</li><li>James</li></ul></body></html>
### Partials
@@ -143,68 +90,33 @@ Ok, now that we know how to make layout templates by passing the result of one t
Here is the data we want to render:
- var links = [
- {name: "Google", link: "http://google.com/"},
- {name: "Github", link: "http://github.com/"},
- {name: "nodejs", link: "http://nodejs.org/"},
- {name: "HowToNode.org", link: "http://howtonode.org/"}
- ];
+<haml-for-javascript/data.js>
First we'll make a partial to render each link by itself and save it as `link.haml`:
- #!haml
- %li
- %a{href: link}&= name
+<haml-for-javascript/link.haml>
Then we'll make a page to render the links and save it as `links.haml`:
- #!haml
- %h1 Links
- %ul
- :each link in links
- = partial("link", link)
-
-Since partials aren't built into [haml-js][], then we'll have to implement it in our framework. But don't worry, it's not hard.
-
-We're starting to nest pretty deeply, so we'll shift to parallel file loading for the template sources. We'll pre-compile the templates while we're at it:
-
- var template_names = ["layout", "link", "links"];
- var counter = template_names.length;
- var templates = {};
- template_names.forEach(function (name) {
- File.read(name + ".haml").addCallback(function (text) {
- templates[name] = Haml.compile(text);
- counter--;
- if (counter <= 0) {
- render_page();
- }
- });
- });
+<haml-for-javascript/links.haml>
+
+Since partials aren't built into [haml-js][], then we'll have to implement it in our framework. But don't worry, it's not hard. First we want to load and compile the templates. And this time we'll do it right using non-blocking I/O. This code snippet will load the three haml files and compile them. Once all three finish, the next step is called.
+
+<haml-for-javascript/step3.js#setup>
Now we can make a render function that knows how to load the saved, compiled templates:
- function render(name, locals) {
- return Haml.execute(templates[name], null, locals);
- }
+<haml-for-javascript/step3.js#render>
We're all set to define the `render_page` function referenced in the parallel loading part:
- function render_page() {
- var html = render("layout", {
- title: "Links",
- contents: render("links", {
- partial: render,
- links: links
- })
- })
- sys.puts(html);
- }
+<haml-for-javascript/step3.js#renderpage>
### Source Code
-You can find the [source code][] of the code in these examples on GitHub.
+You can find the [source code][] of the examples in the panel to the right.
-Also, this blog itself is powered by `haml-js`. You can see the [templates here][] and the [engine here][].
+Also, this blog itself is powered by `haml-js`. You can see the [templates here][].
## Using jquery-haml
@@ -236,12 +148,12 @@ This creates a div element, sets the style on it, and then calls `$.fn.slider` o
A full depth tutorial on this library could go on for pages, but this should be enough to whet your appetite. See the source of the [sample page][] for some more ideas. But since this is more of an easy macro system for programmatically dom-building, then you have full control over every step. I've written entire apps using just nested `jquery-haml` expressions and closures for data storage.
[templates here]: http://github.com/creationix/howtonode.org/tree/master/skin/
-[engine here]: http://github.com/creationix/node-blog/blob/master/build.js
[sample page]: http://static.creationix.com/jquery-haml/examples
-[source code]: http://github.com/creationix/howtonode.org/tree/master/articles/haml-for-javascript/
[node mailing list]: http://groups.google.com/group/nodejs
[here]: http://nodejs.org/api.html#_modules
[ruby]: http://ruby-lang.org/
[HAML]: http://haml-lang.com/
[jquery-haml]: http://github.com/creationix/jquery-haml
-[haml-js]: http://github.com/creationix/haml-js
+[haml-js]: http://github.com/creationix/haml-js
+[jade]: http://jade-lang.com
+[grain]: http://github.com/creationix/grain
View
6 articles/haml-for-javascript/data.js
@@ -0,0 +1,6 @@
+module.exports = [
+ {name: "Google", link: "http://google.com/"},
+ {name: "Github", link: "http://github.com/"},
+ {name: "nodejs", link: "http://nodejs.org/"},
+ {name: "HowToNode.org", link: "http://howtonode.org/"}
+];
View
19 articles/haml-for-javascript/step1.js
@@ -1,12 +1,11 @@
var Haml = require('haml'),
- File = require('file'),
- sys = require('sys');
+ fs = require('fs');
-File.read('layout.haml').addCallback(function (haml) {
- var data = {
- title: "Hello Node",
- contents: "<h1>Hello World</h1>"
- };
- var html = Haml.render(haml, {locals: data});
- sys.puts(html);
-});
+var haml = fs.readFileSync('layout.haml', 'utf8');
+
+var data = {
+ title: "Hello Node",
+ contents: "<h1>Hello World</h1>"
+};
+
+console.log(Haml.render(haml, {locals: data}));
View
29 articles/haml-for-javascript/step2.js
@@ -1,17 +1,16 @@
var Haml = require('haml'),
- File = require('file'),
- sys = require('sys');
+ fs = require('fs');
-File.read('layout.haml').addCallback(function (layout_haml) {
- File.read('users.haml').addCallback(function (users_haml) {
- var data = {
- users: ["Tim", "Sally", "George", "James"]
- };
- var page_data = {
- title: "System Users",
- contents: Haml.render(users_haml, {locals: data})
- };
- var html = Haml.render(layout_haml, {locals: page_data});
- sys.puts(html);
- });
-});
+var layoutHaml = fs.readFileSync('layout.haml', 'utf8');
+var usersHaml = fs.readFileSync('users.haml', 'utf8');
+
+var data = {
+ users: ["Tim", "Sally", "George", "James"]
+};
+var page_data = {
+ title: "System Users",
+ contents: Haml.render(usersHaml, {locals: data})
+};
+var html = Haml.render(layoutHaml, {locals: page_data});
+
+console.log(html);
View
26 articles/haml-for-javascript/step3.js
@@ -1,12 +1,13 @@
var Haml = require('haml'),
- File = require('file'),
- sys = require('sys');
+ fs = require('fs');
+//setup
var template_names = ["layout", "link", "links"];
var counter = template_names.length;
var templates = {};
template_names.forEach(function (name) {
- File.read(name + ".haml").addCallback(function (text) {
+ fs.readFile(name + ".haml", 'utf8', function (err, text) {
+ if (err) throw err;
templates[name] = Haml.compile(text);
counter--;
if (counter <= 0) {
@@ -14,28 +15,19 @@ template_names.forEach(function (name) {
}
});
});
-
+//render
function render(name, locals) {
return Haml.execute(templates[name], null, locals);
}
-
-var links = [
- {name: "Google", link: "http://google.com/"},
- {name: "Github", link: "http://github.com/"},
- {name: "nodejs", link: "http://nodejs.org/"},
- {name: "HowToNode.org", link: "http://howtonode.org/"}
-];
-
+//renderpage
function render_page() {
var html = render("layout", {
title: "Links",
contents: render("links", {
partial: render,
- links: links
+ links: require('./data')
})
- })
- sys.puts(html);
+ });
+ console.log(html);
}
-
-
Please sign in to comment.
Something went wrong with that request. Please try again.