backbone.js, connecting same collection model for 2 different views - backbone.js

I have a collection, and I'm trying to share information concerning the current model being selected between two different views
-->TO PUT IT SIMPLY, I WANT TO BE ABLE TO ACCESS THE MODEL SELECTED IN ONE VIEW FROM ANOTHER VIEW AND CHANGE/ASSIGN THE ATTRIBUTES OF THE MODEL
The first view is defined with:
App.Views.Person = Backbone.View.extend({
tagName: 'a',
template: template('personTemplate'),
initialize: function(){
this.model.on('change', this.render, this);
this.model.on('destroy', this.remove, this);
},
render: function() {
this.$el.html( this.template(this.model.toJSON()) );
this.input = this.$('.view');
return this;
},
the second view is defined with:
App.Views.App = Backbone.View.extend({
el: 'html',
initialize: function(){
_.bindAll(this,"render");
},
render: function() {
return this;
},
and I created my views with the following
addPersonView = new App.Views.AddPerson({ collection: peopleCollection });
appView = new App.Views.App({ model: person, collection: peopleCollection });
How do I make it so that the model selected in the 2nd view is the same as the model in the first view as pulled from my collection --> for example, when I type something into the input box on my bottom view, I want to be able to use: this.set.model({name:title}) and for this to set the model attribute for the element (associated with a model) that is selected in my top view, but using this.set.modelis not choosing the correct model that is selected in my first view
for further reference and confusion: my models are being added to my PeopleView with the following code which i'm loading from an array;
App.Views.People = Backbone.View.extend({
// tagName: '',
initialize: function() {
var i = 1;
while(i < size)
{
var person = new App.Models.Person({ url: jsArray[i] });// creating a new person object..
this.collection.add(person);
i++
}
this.collection.on('add', this.addOne, this);
console.log(jsArray[1]);
// listeners/anouncers for the collection on add..
},
// refactored render method...
render: function() {
this.collection.each(this.addOne, this);
return this;
},
// called from render method of collection view..
addOne: function(person) {
var personView = new App.Views.Person({ model: person, vent: vent });
this.$el.append(personView.render().el);
}
});

I resolved this by using 'vents' so to speak --> (awesome link) the vents provide ways for views to communicate etc
http://lostechies.com/derickbailey/2012/04/03/revisiting-the-backbone-event-aggregator-lessons-learned/, or an application level aggregator like so:
MyApp.vent = _.extend({}, Backbone.Events);
MyApp.vent.on("some:event", function(){
alert("some event was fired!");
});
MyApp.vent.trigger("some:event");

Related

Render Collection model in backbone

Generally when design view for Collection(s), I would bind the collection to the view, and register related events to the collection like this:
var Book = Backbone.Model.extend({});
var BookList = Backbone.Collection.extend({
model: Book,
url: "/books"
});
var BookListItemView = Backbone.View.extend({
mtemplate: _.template($('#tpl_book_item').html()),
render: function () {
this.$el = $(this.mtemplate(this.model.toJSON()));
return this;
}
});
var BookListView = Backbone.View.extend({
el: '#content',
initialize: function () {
this.listenTo(this.collection, 'add', this.render);
this.listenTo(this.collection, 'remove', this.render);
},
render: function () {
this.$el.empty();
this.collection.each(function (item) {
this.$el.append(new BookListItemView({model: item}).render().$el);
}, this);
return this;
}
});
Use:
var books = new BookList();
var bookListView = new BookListView({
collection: books
});
books.fetch();
It worked as expected: render every book as defined in the template. However I found that there is a slight stuck in the page.
I am not sure if this is caused by the re-rendering the view? As shown, when the books.fetch complete, it will add books to the collection of books, for each book item, an add event will be triggered, then I will re-render the page by removing the exist item and iterate the collection.
Which means once there are 10 books, there will be 1+2+3+4...+10 loops for the BookListView.
I my opinion, once the add event triggered, I should not refresh the whole list but just add a new view to the BookListView, but how about the remove event, it seems that Backbone does not provide any internal method to get the view from the model, so once a model to be removed, I can not get the related view.
How do you handle this kind of suitation?
Do not bind your add to the render function. Instead create a dedicated add method for that.
var Book, BookList, BookListItemView, BookListView;
Book = Backbone.Model.extend({});
BookList = Backbone.Collection.extend({
model: Book,
url: "/books"
});
BookListItemView = Backbone.View.extend({
mtemplate: _.template($("#tpl_book_item").html()),
initialize: function() {
this.model.on("remove", this.remove);
},
render: function() {
this.$el = $(this.mtemplate(this.model.toJSON()));
return this;
}
});
BookListView = Backbone.View.extend({
el: "#content",
initialize: function() {
this.listenTo(this.collection, "add", this.addItem);
},
render: function() {
this.$el.empty();
this.collection.each((function(item) {
this.addItem(item);
}), this);
return this;
},
addItem: function(item) {
this.$el.append(new BookListItemView({
model: item
}).render().$el);
}
});
Let the models own View handle its own remove event.

Backbone.js change view variable without reinitalizing

I have a Backbone.js app that I am developing (first one so forgive me if this is a silly question). I have a header view (background and a title). I have a model which updates the title depending on the view/template rendered. I also listening for a change and re-rendering the view to display the new title. This works however the entire view is re-rendered (I know why it is rendering the entire view again) but wondering if there is a way to just update the title?
Heading View:
var HeadingLabelView = Backbone.View.extend({
el: '.heading-label-wrapper',
initialize: function(){
_.bindAll(this, "render");
this.model.bind('change', this.render);
},
render: function() {
var that = this;
var template = _.template($("#heading-label-template").html(), that.model.toJSON());
that.$el.html(template);
}
});
Login View:
var LoginView = Backbone.View.extend({
el: '.page',
render: function() {
pageHeading.set({ name: "Log In" });
var that = this;
var template = _.template($("#login-template").html(), { });
that.$el.html(template).trigger('create');
}
});
I think you can do this by listening only on the change event for the name property of the model
var HeadingLabelView = Backbone.View.extend({
el: '.heading-label-wrapper',
initialize: function(){
_.bindAll(this, "render");
this.model.bind('change', this.render);
this.model.bind('change:name', this.renderTitle);//listen to changes on the 'name' property
},
render: function() {
var that = this;
var template = _.template($("#heading-label-template").html(), that.model.toJSON());
that.$el.html(template);
},
renderTitle: function(model,value,options) {
//assuming your title tag can be located with 'heading-label-title' id, this will update the title only
this.$("#heading-label-title").html(value);
},
});
Check out the Catalog of Build-in Events on the backbonejs.org, you should be able to listen only to changes of a specific property of the model.

Backbone collection full of data, but models are empty

With Backbone.js, I'm trying to bootstrap my data into a collection. My bootstrap looks like log.reset( <JSON> );
When I console.log my collection I see a bunch of objects full of data. The problem is when I console.log on the individual models in the loop, I see a bunch of empty objects with no data. The data is all there in the collection, but I can't get it to pass into my template on each forEach pass. I used the exact same code structure on another part of my project to render a collection view which works perfectly... I don't know why this one isn't working.
Note that I am listening for the reset event on the collection.
//Log Model
var LogItem = Backbone.Model.extend({});
var logItem = new LogItem();
//Log Collection
var Log = Backbone.Collection.extend({
model: LogItem
});
var log = new Log();
//Log Item View
var LogItemView = Backbone.View.extend({
tagName: 'tr',
template: _.template($('#log-item-template').html()),
render: function(){
var attributes = this.model.toJSON();
this.$el.html(this.template( attributes ));
console.log( this.model.toJSON() ); //This shows a bunch of empty objects
return this;
}
});
//Log View
var LogView = Backbone.View.extend({
el: '#log',
initialize: function() {
this.collection.on('reset', this.render, this);
},
render: function(){
this.addAll();
console.log( this.collection.toJSON() ); //This shows objects full of data
},
addOne: function(food) {
var logItemView = new LogItemView({model: logItem});
this.$el.append(logItemView.render().el);
},
addAll: function() {
this.$el.html('');
this.collection.forEach(this.addOne, this);
}
});
var logView = new LogView({collection: log});
How can I fix my empty models?
While building your subviews, your addOne method declares a food argument but you call your LogItemView constructor with {model: logItem}
Try
addOne: function(food) {
var logItemView = new LogItemView({model: food});
this.$el.append(logItemView.render().el);
}

getting model data to a view backbone.js

I am trying to understand the relationship between a model and a view. I've tried building a model and view to render that model.
I get the error Cannot call method 'toJSON' of undefined which I understand as the actual instance of the model is not being sent to the view.
I feel there is something missing in the initialize of the view?
The Model:
var sticky = Backbone.Model.extend({
defaults: {
title:"",
content:"",
created: new Date()
},
initialize: function() {
console.log("sticky created!");
}
});
The View:
var stickyView = Backbone.View.extend({
tagName:"div",
className:"sticky-container",
initialize: function() {
this.render();
console.log("stickyView created!");
},
render: function() {
$("#content-view").prepend(this.el);
var data = this.model.toJSON(); // Error: Cannot call method 'toJSON' of undefined
console.log(data);
var source = $("#sticky-template").html();
var template = Handlebars.compile(source);
$(this.el).html(template(data));
return this;
}
});
Creating new model and new instance of the view:
var Sticky = new sticky({title:"test"});
var StickyView = new stickyView();
You have to pass your model instance to your view, Backbone will do the rest:
constructor / initialize new View([options])
There are several special options that, if passed, will be attached directly to
the view: model, collection, el, id, className, tagName and
attributes.
which means you would create your view like this
var StickyView = new stickyView({model: Sticky});
And while you're at it, you could pass your compiled template and the DOM node you wish to set as your view element (and remove the tagName and className from your view definition) to avoid a strict coupling:
var stickyView = Backbone.View.extend({
initialize: function(opts) {
this.template = opts.template;
this.render();
console.log("stickyView created!");
},
render: function() {
var data = this.model.toJSON();
console.log(data);
this.$el.html(this.template(data));
return this;
}
});
var StickyView = new stickyView({
model: Sticky,
el: '#content-view',
template: Handlebars.compile($("#sticky-template").html())
});

Backbone.js not rendering

My collection is not rendering for some reason. Cannot find out why.
TreeItem = Backbone.Model.extend({
});
TreeList = Backbone.Collection.extend({
model: TreeItem,
url: "/get_tree_list"
});
window.tree_list = new TreeList();
// VIEW
window.TreeItemView = Backbone.View.extend({
tagName: 'li',
initialize: function(){
_.bindAll(this, 'render');
},
render: function(){
$(this.el).html('<span>'+this.model.get('title')+'</span>');
return this;
}
});
window.TreeListView = Backbone.View.extend({
el: "#tree-structure",
events: {
},
initialize: function() {
_.bindAll(this, 'appendItem', 'render');
tree_list.bind('add', this.appendItem);
tree_list.fetch();
this.render();
},
render: function() {
tree_list.each(this.appendItem);
return this;
},
appendItem: function(item){
var tree_item_view = new TreeItemView({
model: item
});
$(this.el).append(tree_item_view.render().el);
}
});
var tree_list_view = new TreeListView;
Backbone.js provides a lot to be interpreted that's where people new go wrong. Your mistake is fundamental in nature. You tie the View directly to the model
see initialize function where a instance of collection is rendered!!
Always and anywhere you create model, collection pass then as parameters to the constructor of views. Check my fiddle
Never call render inside model, view or collection. They must be inside application file
JsFiddle
http://jsfiddle.net/35QGM/

Resources