Gunther

Conquer Your Views. Frustration Free.


Example

Hello World

Gunther makes it easy to bind to a model's attributes, right from your view. You retain full control over your output, because of Gunther's functional, expressive DSL. No wonky properties or hidden logic. No compilation.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Create a template
template = new Gunther.Template (hello) ->
  @element 'form.hello', ->

    # Say hi!
    @p -> @boundText hello, 'who', -> "Hi, #{hello.get 'who'}!"

    # Add a form element to ask for a name
    @div -> @input ->

      # Bind the value to the name
      @boundAttribute 'value', hello, 'who'

      # Change the name on keyup
      @on 'keyup', (e) -> hello.set 'who', ($ e.target).val()


# A simple model to keep track of who you are
class Hello extends Backbone.Model

# Render the template
template.renderInto ($ '#example1-output'), new Hello who: 'You'

Output

Explanation

See how the bindings work? @boundText takes care of everything for you, it binds to the hello model, and updates its text node when the you attribute changes. For additional awesome, you can add a generator method to transmogrify this text based on whatever criteria you choose. @boundAttribute works the same, it binds the value attribute of the input to the name. Bindings are unidirectional.

Handling events is even easier. Nothing but a simple method, @on, which, as you may have guessed, is little more than a wrapper for jQuery's methods of the same name. You have the hello model right there in your event handler scope to do with as you please. Of course you can still offload event handling to outside of your templates.

Why Gunther

Manageable

While Backbone.js offers a simple templating solution for its views, it is nothing more than string interpolation. You will have to manage these templates somehow, essentially including large chunks of string based markup somewhere in your code base. Rendering them is a one-time operation. After the fact, your view layer ends up in charge of managing the resulting DOM.

Gunther's templates are different. They are pure code, so you can manage them along with your views and models. They are "live", and manage themselves. The library itself is tiny, has a simple syntax, yet supports event handling and data binding.

Proper Event Handling

One of the bigger challenges in any (web-) application is handling user input. In Backbone.js this is typically done with event handlers in the View layer. These handlers can have a hard time figuring out what model relates to what DOM event. You end up adding classes and ids to elements just to translate those back into a model elsewhere.

In Gunther, you can manage events right inside of your views. Since Gunther is never compiled, and you retain scope, you will still have all data you need right there. A change in an input element is easily translated to a model's property, which is then live-updated elsewhere.

Live Data

Because your models live, you spend a lot of time updating your views and keeping track of state. When your models become more complex, your controlling logic will grow exponentially. Even in "live" frameworks such as AngularJS outside logic can be needed to manage certain properties such as a "checked" attribute.

Gunther tries to make this easier with its declarative nature. If you need an element to change depending on a model's properties, you declare that when creating it. You can toggle and set classes, attributes, and properties with ease. What's even better is that no additional rendering is needed. Gunther will simply only update that part of the DOM that actually changed.

Example

To Do list

The ubiquitous todo list example. It's one of the simpler UIs imaginable, yet it is definitely "real world". Using Gunther it looks like this.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# The template for the list of to do's, using Gunther's subviews
template = new Gunther.Template (toDoList) ->
  @element 'form.todo', ->

    # Button to archive items that are done
    @p -> @element 'a.archive-todos', ->
      @on 'click', -> do toDoList.archive
      @text ' Archive'

    # The list of elements (see toDoItemTemplate below)
    @list 'div.items', toDoList, toDoItemTemplate

    # Input to create new items
    @element 'input#add-todo', ->

      # Create a new todo when return is pressed
      @on 'keypress', (e) ->
        if e.keyCode isnt 13 then return else do e.preventDefault

        toDoList.addToDo ($ e.target).val()
        ($ e.target).val ''

# A single todo item's template (See @list above)
toDoItemTemplate =  new Gunther.Template (toDo) ->
  @element 'div.todo-item.checkbox', ->

    # Toggle "done" class when todo is done
    @toggleClass 'done', toDo, 'done'

    # Label wrapper
    @label ->

      # Checkbox
      @element 'input[type=checkbox]', ->

        # Toggle done state
        @on 'change', (e) -> toDo.set 'done', !(toDo.get 'done')

        # Bind the checked state to the "done" attribute
        @boundAttribute 'checked', toDo, 'done'

      # Text for the label
      @text toDo.get 'what'

# Models
class ToDo extends Backbone.Model
class ToDoList extends Backbone.Collection
  model: ToDo

  # Create a new todo
  addToDo: (what, done = false) -> @add what: what, done: done

  # "Archive" items that are done
  archive: () -> @remove @where done: true

# Some sample data
toDoList = new ToDoList
toDoList.addToDo 'Get Groceries'
toDoList.addToDo 'Do Dishes'
toDoList.addToDo 'Call Mom', true

# Render the template
template.renderInto ($ '#example2-output'), toDoList

Output

Explanation

In this example, you'll probably be drawn to the @list statement. Its function is simple, to set up a repeating set of elements that match those of a Backbone collection.

It manages this by accepting both a Collection, and a Gunther Template for every child item. You can specify all of this inline if you so choose, but here the child template, toDoItemTemplate, is in a separate variable. Obviously, this is geared towards re-use of your components.

The list view will keep track of both the set of items itself (addition/removal), and the order in which they should appear. If you call sort(), your items will be re-ordered if necessary.

Another method that is of importance here is the @toggleClass inside of toDoItemTemplate. As you might expect, it toggles (adds and removes) a class, in this case done based on a boolean attribute. As with other things this is bound to a model. If the ToDo item changes its done state, the class will be added or removed.

Flexible

Gunther is a powerful templating library for Backbone.js. It brings live binding in a simple, yet powerful, code-centric based language.

Where other templating tools offer interpreted string templates, Gunther has a novel approach that is easy to create and manage, yet powerful. It does not introduce new HTML attributes, nor does it require any changes to other layers of your application.

Functional

Gunther is entirely functional in its approach. There's no interpolated string based language, nor is there any non-standard markup attributes.

Make your view layer work for you, not the other way around.

Fun

Write views that take care of themselves, without the need to go them with jQuery and state machines. All templating is declarative, aimed at taking full advantage of CoffeeScript's notational power.

Gunther will keep track of your models for you, and change text, properties, or even entire views when things change.

Example

Partials

Gunther allows you to register "partials" to create reusable components.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Add a partial that renders a button, with a handler that is triggered when
# the button is clicked
Gunther.addPartial 'btn', (text, handler) ->

  # Set up the actual button
  @element 'button.btn.btn-default', ->
    @on 'click', handler
    @text text

# Create a template
template = new Gunther.Template (hello) ->
  @btn 'Click me', (e) -> alert 'I was clicked...'
  @btn 'No, click ME!', (e) -> alert 'Great clicking there'

# Render the template
template.renderInto ($ '#example3-output')

Output

Explanation

Partials make it easy to create re-usable components. This example shows a simple button, but anything that you can put in a template, can be used as a partial.

The DSL that Gunther exposes through @div, @p, @a, etc.? Those are partials too. Gunther simply adds one for every HTML5 element there is, wrapping them to @element()