Reputation: 11125
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
<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>
Here's all i want the application to do.
User Types a name(or some alphanumeric string) and clicks submit.
The value(which is what they call model i suppose) after validation will be sent to restful service.
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
//store a global reference to model
window["model"] = Backbone.Model.extend({
defaults: { name: "Type your name"
},
validate: function () {
}
});
//store a global reference to view
window["view"] = Backbone.View.extend({});
nothing in the view to say :(
//when every thing is ready kick of the application
$(document).ready(function () {
var modelInstance = new model();
});
so do i add click event to the button in application.js or model.js.which is the convention/best practice?
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
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
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