Backbone Router

by Joshua McNeese

HTML

<script src="https://cdn.jsdelivr.net/g/[email protected],[email protected],[email protected],[email protected],[email protected]"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/bootstrap/3.3.6/css/bootstrap.min.css">
<nav class="navbar navbar-default navbar-fixed-top">
  <div class="container">
    <ul class="nav navbar-nav pull-left">
      <li><a href="#posts"><span class="glyphicon glyphicon-list-alt"></span> Posts</a></li>
    </ul>
    <ul class="nav navbar-nav pull-right">
      <li><a href="#posts/add"><span class="glyphicon glyphicon-plus-sign"></span> Add New</a></li>
    </ul>
  </div>
</nav>
<div id="content"></div>
<script id="post-template" type="text/x-handlebars-template">
  <h1 class="title">{{title}} by {{author}}</h1>
  <div class="body">
    {{body}}
  </div>
  <a href="#posts/{{id}}/edit" title="Edit"><span class="glyphicon glyphicon-pencil"></span> Edit</a>
</script>
<script id="post-form-template" type="text/x-handlebars-template">
  <input type="hidden" name="id" value="{{id}}" />
  <div class="form-group">
    <label for="title">Title</label>
    <input type="text" class="form-control" name="title" placeholder="Title" value="{{title}}" />
  </div>
  <div class="form-group">
    <label for="body">Body</label>
    <input type="textarea" class="form-control" name="body" placeholder="Body" value="{{body}}" />
  </div>
  <div class="form-group">
    <label for="author">Author</label>
    <input type="text" class="form-control" name="author" placeholder="Author" value="{{author}}" />
  </div>
  <button type="submit" class="btn btn-default">Submit</button>
</script>

CSS

body {
  padding: 40px 0 0 10px;
}

JavaScript

var PostModel = Backbone.Model.extend({
  defaults: {
    id: '',
    title: 'No title',
    body: 'No body',
    author: 'No author'
  }
});

var PostView = Backbone.View.extend({
  tagName: 'li',
  className: 'post',
  template: Handlebars.compile($('#post-template').html()),
  initialize: function() {
    this.listenTo(this.model, 'change', this.render);
    this.render();
  },
  render: function() {
    this.$el.html(this.template(this.model.toJSON()));
  }
});

var PostsCollection = Backbone.Collection.extend({
  model: PostModel
});

var PostsView = Backbone.View.extend({
  tagName: 'ul',
  className: 'posts',
  initialize: function() {
    this.listenTo(this.collection, 'update reset', this.render);
    this.render();
  },
  render: function() {
    var $el = this.$el;
    this.collection.each(function(postModel) {
      var postView = new PostView({
        model: postModel
      });
      $el.append(postView.el);
    });
  }
});

var FormView = Backbone.View.extend({
  tagName: 'form',
  className: 'post-form',
  template: Handlebars.compile($('#post-form-template').html()),
  events: {
    "submit": "onSubmit"
  },
  initialize: function() {
    this.render();
  },
  render: function() {
    this.$el.html(this.template(this.model ? this.model.toJSON() : {}));
  },
  setModel: function(model) {
    this.model = model;
    this.render();
  },
  onSubmit: function(e) {
    e.preventDefault();
    var data = {};
    _.forEach(this.$el.serializeArray(), function(field) {
      if (field.value) {
        data[field.name] = field.value;
      }
    });
    if (this.model && this.model.get('id')) {
      this.model.set(data);
    } else {
      this.collection.create(data);
    }
  }
});

var PostsRouter = Backbone.Router.extend({
  // the internal 'routes' parameter associates any hash keyword to a function
  routes: {
    "": "index",
    "posts": "index",
    "posts/add": "add",
    "posts/:id/edit": "edit"
  },
  initialize: function() {
	 ...