/bobtail

A lightweight CoffeeScript library/DSL for reactive programming and declaratively building scalable web UIs

Primary LanguageJavaScriptMIT LicenseMIT

bobtail Build Status Bower version

A lightweight CoffeeScript library/DSL for reactive programming and for declaratively building scalable web UIs.

Highlights

  • Library of reactive programming primitives
  • Declarative DOM construction
  • Scalable in both performance and application architecture
  • Simple, no magic, no new template language, all CoffeeScript
  • Tested with Chrome, Firefox, Safari, and IE10
  • Available via Bower and cdnjs
  • Works with jQuery
  • MIT license

Example: To-Do List

You can play with this example on jsFiddle, see a complete TodoMVC example, or head directly to the tutorial.

class Task {
  constructor(descrip, priority, isDone) {
    this.descrip = rx.cell(descrip);
    this.priority = rx.cell(priority);
    this.isDone = rx.cell(isDone);
  }
}

const tasks = rx.array([
  new Task('Get milk', 'important', false),
  new Task('Play with Reactive Coffee', 'critical', false),
  new Task('Walk the dog', 'meh', false)
]);

// Our main view: a checklist of tasks, a button to add a new task, and a task
// editor component (defined further down).

const main = function() {
  const currentTask = rx.cell(tasks.at(0)); // "View model" of currently selected task

  return $('body').append(
    div({class: 'task-manager'}, [
      h1(x.bind(() => [`${tasks.length()} task(s) for today`])),
      ul({class: 'tasks'}, tasks.map(function(task) {
        return li({class: 'task'}, [
          input({type: 'checkbox', init() { return this.change(() => task.isDone.set(this.is(':checked'))); }}),
          span({class: 'descrip'}, rx.bind(() => `${task.descrip.get()} (${task.priority.get()})`)),
          a({href: 'javascript: void 0', init() { return this.click(() => currentTask.set(task)); }}, 'Edit')
        ]);})),
      button({init() { return this.click(() => tasks.push(new Task('Task', 'none', false))); }}, [
        'Add new task'
      ]),
      taskEditor({
        task: rx.bind(() => currentTask.get()),
        onSubmit(descrip, priority) {
          currentTask.get().descrip.set(descrip);
          return currentTask.get().priority.set(priority);
        }
      })
    ])
  );
};

// The task editor demonstrates how to define a simple component.

var taskEditor = function(opts) {
  let descrip, priority;
  const task = () => opts.task.get();
  const theForm = form({}, [
    h2('Edit Task'),
    label('Description'),
    (descrip = input({type: 'text', value: rx.bind(() => task().descrip.get())})),
    br(),
    label('Priority'),
    (priority = input({type: 'text', value: rx.bind(() => task().priority.get())})),
    br(),
    label('Status'),
    span(rx.bind(() => [task().isDone.get() ? 'Done' : 'Not done'])),
    br(),
    button('Update')
  ]);
  return theForm.submit(function() {
    opts.onSubmit(descrip.val().trim(), priority.val().trim());
    this.reset();
    return false;
  });
};

$(main);

Next steps

See more quickstart examples, read through the tutorial, or learn more about the motivation and design rationale.

Mascot

Charlie the Bobtail designed by Adele Boulie.