backbonejs - accessing collection in view - javascript

backbonejs and oop js newbie here. i am trying to bind my collection to a view, when i go to my console, i only get this
this is a collection: [object Object]
is there something am i missing here?
var root = "http://jsonplaceholder.typicode.com";
var Post = Backbone.Model.extend({});
var Posts = Backbone.Collection.extend({
model: Post,
url: root + "/posts",
parse: function(response) {
return response;
}
});
var posts = new Posts();
posts.fetch();
// View wrapper to render view child items
var PostsView = Backbone.View.extend({
collection: new Posts(),
initialize: function() {
console.log('this is a collection: ' + this.collection);
},
render: function() {
// STEPS:
// filter through all items in a collection
// for each item, create a new PostView
// append to root element, ex. ul
}
});
var postsview = new PostsView();

When you do 'this is a collection: ' + this.collection you're forcing the collection to be a string, and javascript sees an object and turns it into your [object Object].
The correct way to show a collection as a string is to just its .toJSON() function and do console.log('this is a collection: ' + JSON.stringify(this.collection.toJSON())); but since most devtools are capable of properly showing an object natively you're better off using
console.log('this is a collection: ', this.collection);
That should give you a nice interactive representation of the collection in your console, at least on Chrome.

Related

Backbone 101 - Using JSON data with backbone

I'm in the beginning stages of moving my application to the backbone framework.
I have some data that comes in as json from an ajax call
{f1:"f1_value", f2:"f2_value", f3:"f3_value"},
{f1:"f1_value", f2:"f2_value", f3:"f3_value"},
{f1:"f1_value", f2:"f2_value", f3:"f3_value"},
This data set always has 3 columns but may be as long as needed for each set as far as rows goes.
It is used to populate a div after processing it client side into HTML, which correlatively may extend down as far as needed. I was planning on this data chunk representing one view in the framework.
<div id = "data_hold"></div>
How do I match this up to the framework:
var ModelTest,
CollectionTest,
ViewTest;
ModelTest = Backbone.Model.extend({
});
CollectionTest = Backbone.Collection.extend({
model: ModelTest
}
ViewTest = Backbone.View.extend({
});
Backbone 101:
var ModelTest,
CollectionTest,
ViewTest;
ModelTest = Backbone.Model.extend({ });
// associate your collection with a URL. This is static here; it can be
// passed in as an option using the Collection's initialize function()
// instead.
CollectionTest = Backbone.Collection.extend({
model: ModelTest,
url: 'http://localhost/my_json_source'
});
ViewTest = Backbone.View.extend({
// Have a target to render into. This can be an existing element, as
// here, or it can be dynamically generated and attached to the DOM
// programattically.
el: $('#data_hold'),
// specify than when the collection is updated, call the local render
// method.
initialize: function(options) {
this.collection.bind('reset', _.bind(this.render, this));
},
// Empty the element, then append subsequent rows of the collection
// to it as paragraphs. The '_this = this' idiom allows us to access
// the outside context (the View's context), since the each() call
// will create a new inner context.
render: function() {
var _this = this;
this.$el.html('');
this.collection.each(function(l) {
_this.$el.append('<p>' + l.get('f2') + '</p>');
});
}
});
// initialize the collection and view, then fetch the collection, which
// will trigger the render after the collection has been updated.
$(function() {
ct = new CollectionTest();
vt = new ViewTest({collection: ct});
ct.fetch();
});

Calling Backbone.Model.Save converts child-Backbone.Model to object?

I'm creating a Backbone Model which has a child Backbone Model inside of it:
console.log("inside add item, video:", video instanceof Backbone.Model);
var playlistItem = new PlaylistItem({
video: video,
title: video.get('title')
});
afterwards, I save it:
playlistItem.save({}, {
success: function() {
console.log("Successfully saved.");
playlistItem.get('video').get('title');
}
});
In this example, I encounter an error -- video is not an instanceof Backbone.Model after calling save. Why?
I think you will need to override parse and toJSON.
toJSON: function() {
var json = Backbone.Model.prototype.toJSON.call(this);
// replace backbone model with json.
json.video = this.get('video').toJSON();
return json;
},
parse: function(data) {
// take json of video and set into model.
this.get('video').set(data.video);
delete data.video;
return data;
},
If you don't parse the json data like this, backbone is going to take the 'video' object from the json and overwrite your Backbone model.

Backbone Nested Collections

i'm trying to populate a nested collection that's inside a model, and taht last model inside another collection.
The code is the following
App.Models.Bed = Backbone.Model.extend();
App.Collections.Beds = Backbone.Collection.extend({
model: App.Models.Bed,
initialize: function(models, options){
this.room = options.room;
}
});
App.Models.Room = Backbone.Model.extend();
App.Collections.Room = Backbone.Collection.extend({
url: 'rooms/',
initialize: function(){
this.on('reset', this.getBeds, this);
},
getBeds: function(){
this.each(function( room ){
room.beds = new App.Collections.Beds([], { room: room});
room.beds.url = 'rooms/' + room.id + '/beds';
room.beds.fetch();
console.log(room.beds.toJSON());
});
}
});
Now, if I execute:
var rooms = new App.Collections.Room();
rooms.fetch();
rooms.toJSON();
It gives me back just the rooms populated, but no beds property on each bed.
The wired thing is that it makes the request to the server at /rooms/1/beds and I get back each bed.
Is it populating the beds collection?
Am I doing something wrong?
Thanks for your time mates.
Looks like you need to pass in the Room Model to the Room Collections.

How do I render multiple records out to a html table with Backbone.js ?

var ContractModel = Backbone.Model.extend({
url: "${g.createLink(controller:'waiverContract', action:'index')}"
})
var contract = new ContractModel({});
contract.fetch();
var contracts = new Backbone.Collection.extend({
model: contract
});
var ContractView = Backbone.View.extend({
initialize: function(){
this.render();
},
render: function() {
var root = this.$el;
_.each(this.model, function(item) {
var row = '<tr><td>' + item + '</td></tr>';
root.find('tbody').append(row);
});
return this;
}
});
var cView = new ContractView({ model: contract, el: $('#contracts') });
I have Chrome's developer tools open. If I do a console.log(this.model) inside of the render function, I can see a mess of an object, of which the two records are stored in .attributes. But instead of two rows being added to the table, I get 7. 6 of which are objects. (Though I see 9 subobjects in Chrome's console).
Not much of this makes sense to me. Can anyone help me not only get this working, but also understand it? I know that render() fires off as soon as I have instantiated cView, and I know that it's doing the ajax as soon as I do .fetch() into the model. But that's the limit of what I can understand in this.
You should fetch and iterate on the collection, not the model. A model is one "thing" and a collection has many "things". Assuming you are fetching a JSON formatted array into your model, it will end up with properties like "1", "2", and so on, and each of these will just be a normal Javascript object, not a ContractModel instance.
Here is how you might restructure your code:
var ContractModel = Backbone.Model.extend();
var ContractCollection = Backbone.Collection.extend({
//ContractModel class, not an instance
model: ContractModel,
//Set the url property on the collection, not the model
url: "${g.createLink(controller:'waiverContract', action:'index')}"
})
var ContractView = Backbone.View.extend({
initialize: function(){
//Bind the collection reset event, gets fired when fetch complets
this.collection.on('reset', this.render, this);
},
render: function() {
//This finds the tbody element scoped to your view.
//This assumes you have already added a tbody to the view somehow.
//You might do this with something like
//this.$el.html('<table><tbody></tbody></table>');
var $tbody = this.$('tbody');
this.collection.each(function(contract) {
//Add any other contract properties here,
//as needed, by calling the get() model method
var row = '<tr><td>' + contract.get('someContractProperty') + '</td></tr>';
//Append the row to the tbody
$tbody.append(row);
});
return this;
}
});
//Instantiate collection here, and pass it to the view
var contracts = new ContractCollection();
var cView = new ContractView({
collection: contracts,
el: $('#contracts')
});
//Makes the AJAX call.
//Triggers reset on success, and causes the view to render.
//Assumes a JSON response format like:
// [ { ... }, { ... }, ... ]
contracts.fetch();

How do I fetch a single model in Backbone?

I have a Clock model in Backbone:
var Clock = Backbone.Model.extend({});
I'm trying to get an instance of that that has the latest information from /clocks/123. Some things I've tried:
a "class"-level method
Clock.fetch(123)
// TypeError: Object function (){ ... } has no method 'fetch'
creating an instance and then calling fetch on it:
c = new Clock({id: 123})
c.fetch()
// Error: A 'url' property or function must be specified
a collection
I tried creating an AllClocks collection resource (even though I have no use for such a thing on the page):
var AllClocks = Backbone.Collection.extend({
model: Clock,
url: '/clocks/'
});
var allClocks = new AllClocks();
allClocks.fetch(123);
// returns everything from /clocks/
How do I just get one API-backed Clock?
Try specifying urlRoot in the model:
From the docs:
var Book = Backbone.Model.extend({urlRoot : '/books'});
var solaris = new Book({id: "1083-lem-solaris"});
solaris.fetch();
Your second approach is the approach I have used. Try adding the following to your Clock model:
url : function() {
var base = 'clocks';
if (this.isNew()) return base;
return base + (base.charAt(base.length - 1) == '/' ? '' : '/') + this.id;
},
This approach assumes that you have implemented controllers with the hashbang in your URL like so, http://www.mydomain.com/#clocks/123 , but it should work even if you haven't yet.
I personally recommend, following the Model#url method documentation
model = new Model(id: 1)
view = new View(model: model)
collection = new Collection([model])
model.fetch()
in your collection remember to add the collection url:
url: "/models"
and in your View's initialize function do:
this.model.bind("change", this.render)
this way backbone will do an ajax request using this url:
"/models/1"
your model will be updated and the view rendered, without modifying Collection#url or Model#urlRoot
note:
sorry this example came out in coffee script, but you can easily translate it to js adding var statements
var Person = Backbone.Model.extend({urlRoot : '/person/details'});
var myName = new Person({id: "12345"});
myName.fetch();
As a result you make a Ajax request on the
URL http://[domainName]/person/details/id
and you have the JSON response back.
Enjoiiii !!!
...and do this if you don't want the trailing slash on the model urlRoot:
url : function() {
return this.urlRoot + this.id;
},
You probably should be accessing the object trough a collection and keeping it in the collection all the time. This is how to do it:
var AllClocks = Backbone.Collection.extend({
model: Clock,
url: '/clocks/'
});
var allClocks = new AllClocks();
my_clock = allClocks.add({id: 123});
my_clock.fetch()
I want to use RESTful url,but I couldn't understand why 'postId' can't be added to base url.
var PostModel = Backbone.Model.extend({
urlRoot: 'getBlogPost',
defaults: {
postTitle: "defaultTitle",
postTime: "1970-01-01",
postContent: "defaultContent",
postAuthor: "anonymous"
}
});
var post = new PostModel({
postId: 1
});
alert(post.url());
Then I know only after I set 'idAttribute' as 'postId' in Model can I get the right url.
like this:
var PostModel = Backbone.Model.extend({
idAttribute: 'postId',
urlRoot: 'getBlogPost',
defaults: {
postTitle: "defaultTitle",
postTime: "1970-01-01",
postContent: "defaultContent",
postAuthor: "anonymous"
}
});

Categories

Resources