As templating libraries go, you can’t go far wrong with Jade. It’s easily installable via npm npm install jade
, and is a common templating solution used with the node.js MVC framework Express. The format is very similar to Haml and is well documented.
As well being able to use coffeescript and stylus within jade templates jade has a very consice way of expressing html content. There are parts of jade that are most usefull on the server side, but plenty of stuff that is still useful on the client side like mixins and includes. If your spine app is complimenting a node.js app that uses jade it can be pretty awesome to only have to handle one type of view template!
The simplest way of using jade is via hem which will automatically compile your jade views for you. simply include your .jade
files in the view directory of your spine app and require them from your controllers.
class Contacts extends Spine.Controller
constructor: ->
super
@render()
render: ->
@html require('views/contacts')
The syntax is fairly straightforward, if you are familiar with Haml or Zen-coding you’ll pick it right up:
-var klass = (type == null ? null : 'changeBox')
div(class=klass)
if type == null
input(type="text", name="searchField", placeholder="find by name..", title="find by name")
a.add.createOriginTrigger(href="#", title="Create New Contact") +
else
div.changeControls
a(href="#", class="change contactChange") switch
a(href="#", class="edit contactEdit") edit
p
span.subLabel Name
span.val #{name}
p
span.subLabel Phone
span.val #{phone1}
input.contactId(type="hidden", value=id)
Data association is up to you to handle, if needed, in you controller logic. There are numerous ways to do this, for example:
//= CoffeeScript
elements:
'table' : 'contactsTable'
events:
'.itemRef': 'edit'
'.delete' : 'deleteItem'
list: ->
items = Contact.all()
listContent = ''
for item in items
listContent += require('views/contact/item')(item)
@contactsTable.html listContent
edit: (e) ->
e.preventDefault()
itemId = $(e.target).parent('tr').data('itemid')
# or
itemId = $(e.target).attr('href')
...
delete: (e) ->
e.preventDefault
itemId = $(e.target).parent('tr').data('itemid')
...
the the views/contact/item
might look like this
tr.item(data-itemid=id)
td
a.edit(href=id)= name
td= locals.phone
td= locals.email
td
a.delete(alt='delete'): span.icon-erase
Data binding is a very powerful technique for ensuring model data stays in sync with the view. The premise is that controllers bind to model events, re-rendering the view when those events are triggered. Let’s take a simple example, a list of contacts. The controller will bind to the Contact
model’s refresh and change events, which are triggered whenever the model’s data changes. When the event is triggered, the controller re-renders the view.
//= CoffeeScript
class ContactsList extends Spine.Controller
constructor: ->
Contact.bind('refresh change', @render)
render: =>
items = Contact.all()
@html = ''
for item in items
@append require('views/contacts')(items)
There are several common binding patterns, see the controller patterns guide for more information.
To use precompiled jade templates in the browser you must include jade’s runtime.js. In Hem you can add this a as a lib in your spine projects slug.json.