Deeptechtons
Deeptechtons

Reputation: 11125

In a Backbone app what is work of model, views and collections by convention

I am right now developing a dead simple application using backbonejs mvc javascript library.Just to show how simple it is here is the html

Sample Html

<div class="container">
    <div>
        <label>
            Name:
            <input id="txtName" type="text" title="Type your name please" /></label>
        <button id="btnSubmit" type="button" value="Submit">
            Submit</button>
    </div>
    <div id="names">
    </div>
</div>

Operation

Here's all i want the application to do.

  1. User Types a name(or some alphanumeric string) and clicks submit.

  2. The value(which is what they call model i suppose) after validation will be sent to restful service.

  3. Service will return the same string along with status of database save operation.

I am now confused as to where the click event will handled(is it in the model?), after that where should the render method be called?(is it in views). Below you will find the script i had managed up until now

Model.js

//store a global reference to model
    window["model"] = Backbone.Model.extend({

        defaults: { name: "Type your name"
        },
        validate: function () {

        }

    });

View.js

//store a global reference to view
window["view"] = Backbone.View.extend({});

nothing in the view to say :(

Application.js

//when every thing is ready kick of the application
$(document).ready(function () {


    var modelInstance = new model();


});
  1. so do i add click event to the button in application.js or model.js.which is the convention/best practice?

  2. Will it be possible for me to render the names collection returned from service into #names and status of the database insertion into another div somewhere up above the container? Can the view render both views?

Upvotes: 0

Views: 565

Answers (2)

Sander
Sander

Reputation: 13431

i would do the click in the view you would need 2 views in my eyes, 1 is an appview that holds your entire app the other is just a view for each usermodel you render out in your list .

here is your user model

var User = Backbone.Model.extend({
  defaults: {
    id: 0,
    name: 'no-name'
  }
});

here is your collection

var Users = Backbone.Collection.extend({

  model: User,

  create : function(model, options) {
    var coll = this;
    options || (options = {});
    if (!(model instanceof Backbone.Model)) {
      model = new this.model(model, {collection: coll});
    } else {
      model.collection = coll;
    }
    var success = function(savedModel, resp) {
      coll.add(savedModel);
      if (options.success) options.success(nextModel, resp);

      // fire success event
      coll.trigger("savesuccess", savedModel);
    };
    var error = function(resp) {
      if(options.error) options.error(resp);

      // fire error event
      coll.trigger("saveerror");
    }
    return model.save(null, {success : success, error : error});
  }
});

so here is a possible user view

var UserRow = Backbone.View.extend({

  tagName: "li",

  initialize: function(){
    _.bindAll(this, 'render');
    this.model.bind('change', this.render);
  },

  className: "user",

  render: function() {
    var user = this.model;
    $(this.el).html(user.get('name'));
    return this;
  }

});

here is your appView

var AppView = Backbone.View.extend({

  el: 'body',

  events: {
    'click button#btnSubmit': 'addUser'
  },

  initialize: function(){
    this.collection = new Users();
    this.collection.bind('add', this.appendUser);
    this.collection.bind('savesuccess', this.saveSuccess);
    this.collection.bind('saveerror', this.saveError);
    this.counter = 0;
    this.render();
  },

  addUser: function(){
    this.counter++;
    var user = new User();
    user.set({
      id: user.get('id') + this.counter,
      name: $('#txtName', this.el).val()
    });
    this.collection.add(user);
  },

  appendUser: function(user){
    var userRow = new UserRow({
      model: user
    });
    $('ul#names', this.el).append(userRow.render().el);
  },

  saveSuccess: function(user){
    alert('successfully saved, you can append something to the AppView DOM to show that saving was successful ...');
  },

  saveError: function(){
    alert('failed to save, you can append something to the AppView Dom to show that saving failed, or remove the item again ...');
  }
});

here you initialize it all

var App = new AppView();

as you can see, rendering the items itself does not happen after saving it in the database, it is added to the collection, the appView binds to the add event of the collection and appends the new user to your list.

the CRUD server connection works automatically, due to using the create function on the collection.

the idea here is that you don't need to user backbone events, trigger an event from your collections successful save or error save, and let any view bind to that event to make something happen on the screen when save was a success or not.

Upvotes: 2

Brian Genisio
Brian Genisio

Reputation: 48137

So, here is a disclaimer: If this is all your app is doing, then Backbone is way too much ceremony. When the app gets more complex with more moving parts, Backbone becomes pretty amazing.

That being said, I have created a jsFiddle to highlight how you might use Backbone for what you want to do: http://jsfiddle.net/BrianGenisio/CZwnk/4/

Basically, you have a Person model and a People collection to hold the Person models. You then have three views: NewPersonView which is the form for entering your data, which is responsible for adding new items to the People collection. Then you have a PeopleView view which is responsible for showing People collection, which will watch the collection and show any additions. Finally, is the PersonView which is responsible for showing an individual Person model.

When it all comes together, it looks a little something like this:

HTML:

<script id="new_person_template" type="text/template">    
    <label>
        Name:
        <input id="txtName" type="text" title="Type your name please" />
    </label>
    <button id="btnSubmit" type="button" value="Submit">Submit</button>
</script>

<script id="person_template" type="text/template">    
    Hello, my name is <%= name %>
</script>

<div id="container">

</div>

JavaScript

window.app = {};

window.app.Person = Backbone.Model.extend({
    defaults: { name: "Type your name" },
    validate: function () { }
});

window.app.People = Backbone.Collection.extend({
    model: window.app.Person
});

window.app.NewPersonView = Backbone.View.extend({
    template: _.template($("#new_person_template").html()),
    initialize: function () {
        _.bindAll(this, 'submit');
    },
    events:
    {
        "click #btnSubmit": "submit"
    },
    render: function () {
        $(this.el).html(this.template());
        return this;
    },
    submit: function (x, y, z) {
        // If you want this to go up to the server and sync, do this instead:
        // this.model.create({name: $("#txtName").val()});
        // but since we don't really have a server right now, we'll just create and add
        var person = new window.app.Person({name: $("#txtName").val()});
        this.model.add(person);
    }
});

window.app.PersonView = Backbone.View.extend({
    tagname: "li",
    template: _.template($("#person_template").html()),
    render: function() {
        $(this.el).html(this.template(this.model.toJSON()));
        return this;
    }
});

window.app.PeopleView = Backbone.View.extend({
    tagName: "ul",

    initialize: function() {
        _.bindAll(this, "render", "renderPerson");
        this.model.bind("add", this.renderPerson);
    },

    render: function() {
       console.log("rendering");
       this.model.each(this.renderPerson);
       return this;
    },

    renderPerson: function(person) {
        var personView = new window.app.PersonView({model: person});
        $(this.el).append(personView.render().el);
    }
});


$(document).ready(function () {

    var people = new window.app.People();
    var newPersonView = new window.app.NewPersonView({model: people});
    var peopleView = new window.app.PeopleView({model: people});

    $("#container").html(newPersonView.render().el);
    $("#container").append(peopleView.render().el);
});

Upvotes: 5

Related Questions