Question

I'm building a simple Backbone app where I mainly have a view with a list of books (book name + cover image) and another view where I want to add new books to the list.

When I use a sample data the view with the books renders properly, but when I try to add books to the list it doesn't work and I don't know which is the problem.

Here is the JSFiddle http://jsfiddle.net/swayziak/DRCXf/4/ and my code:

HTML:

   <section class="menu">
      <ul class="footer"> 
        <li><a href="">List of Books</a></li>
        <li><a href="#edit">Edit</a></li>
        <li><a href="#about">About</a></li>
      </ul>
   </section>

   <section class="feed"></section> 

   <script id="bookTemplate" type="text/template">
       <img src="<%= image %>"/>
       <h2 class="bookTitle"><%= title %><h2>
   </script>

   <script id="aboutTemplate" type="text/template"> About </script>

   <script id="editTemplate" type="text/template">
       <form id="addBook" action="#">
           <label for="title">Book Title</label><input type="text" id="title">
           <label for="image">Image Link</label><input type="text"/ id="image">
           <button id="add-book">Button</button>                
       </form>
   </script>                

</div>

And the Backbone code:

app = {};

// Sample Data

var books = [
    {title:'Imperial Bedrooms', image:'http://upload.wikimedia.org/wikipedia/en/thumb/e/e8/Imperial_bedrooms_cover.JPG/200px-Imperial_bedrooms_cover.JPG
    },

    {title:'Less than zero', 
    image:'http://d.gr-assets.com/books/1282271923l/9915.jpg' 
    },

];

//Router

app.Router = Backbone.Router.extend({
    routes: {
        '' : 'home',
        'about' : 'about',
        'edit' : 'edit',
    },

    home: function () {
        if(!this.bookListView){
            this.bookListView = new app.BookListView(books);
        }else{
        this.bookListView.render();
        }
    },

    about: function () { 
        if (!this.aboutView) {
            this.aboutView = new app.AboutView();
        }
        $('.feed').html(this.aboutView.render().el);
    },

    edit: function () {
        if (!this.editView) {
            this.editView = new app.EditView();
        );
            $('.feed').html(this.editView.render().el);
    }

});

// Model

app.Book = Backbone.Model.extend({
    defaults: {
        title:'',
        image:'',       
    }
});

// Collection

app.BookList = Backbone.Collection.extend ({
    model: app.Book 
});

// Book View

app.BookView = Backbone.View.extend ({
    tagName: 'div',
    className: 'book',

    template: _.template( $( '#bookTemplate' ).html()),

    render: function() {
        this.$el.html(this.template(this.model.toJSON()));
        return this;
   }
});

// List of Books View

app.BookListView = Backbone.View.extend({
    el: '.feed',

    initialize: function ( initialBooks ) {
        this.collection = new app.BookList (initialBooks);
        this.render();
        this.listenTo( this.collection, 'add', this.renderBook );
    },

    render: function() {
        this.$el.empty();

        this.collection.each(function( item ){
            this.renderBook( item );
        }, this);
    },

    renderBook: function ( item ) {
         var bookview = new app.BookView ({
              model: item
    });            

    this.$el.append( bookview.render().el );
    } 
});

// Add books view

app.EditView = Backbone.View.extend({
  tagName: 'div',
  className: 'edit',

  template: _.template( $( '#editTemplate' ).html()),

  events:{
     "click #add-book":"addBook"
  },

   addBook:function(e){
        e.preventDefault();

        var title = this.$el.find("#title").val();
        var image = this.$el.find("#image").val();
        var bookModel = new app.Book({title:"title",image:'image'});    
    },

  render: function () {
      this.$el.html(this.template());
      return this;
   }
});

// About View

app.AboutView = Backbone.View.extend({
    tagName: 'div',
    className: 'about',

    template: _.template( $( '#aboutTemplate' ).html()),

    render: function () {
        this.$el.html(this.template());
        return this;
     }
});

});

var router = new app.Router();
Backbone.history.start();

I think the problem is related with the Home router, the app.BookListView and the app.EditView, but I'm not sure of that.

Any help is welcomed.

Thanks.

Was it helpful?

Solution

In this example..for simplicity's sake, define a global books collection.

app.books = new app.BookList(books);

Pass your books collection to editView & BookListView in your router:

home: function () {
  if(!this.bookListView) {
     this.bookListView = new app.BookListView({collection:app.books});
  } 
  else {
     this.bookListView.render();
   }
},
edit: function () {
  if (!this.editView)
    this.editView = new app.EditView({collection:app.books}); // your book collection
  $('.feed').html(this.editView.render().el);
}

In you editView you need to make a few changes to your addBook function:

app.EditView = Backbone.View.extend({
 // your other code above
   addBook:function(e){
    e.preventDefault();

    var title = this.$el.find("#title").val(); //could use: this.$('#title').val()
    var image = this.$el.find("#image").val();

    // remove quotes to pass variables
    var bookModel = new app.Book({title:title,image:image}); 

    // this.collection is app.books, your book collection.
    // this will trigger the add event in your BookListView.
    this.collection.add(bookModel);  
  },

});

In your BookListView make the following changes to the initialize function:

app.BookListView = Backbone.View.extend({    

initialize: function() {
    this.render();
    this.listenTo( this.collection, 'add', this.renderBook );
},

Here is a fiddle with the changes: http://jsfiddle.net/9R9zU/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top