I'm trying to learn a little bit of backbone.js and I'm getting stuck on something I think should be fairly simple to figure out. How do I get a list of all model names in a collection?
I'm even copy+pasting from the backbone tutorial:
var Song = Backbone.Model.extend({
defaults: {
name: "Not specified",
artist: "Not specified"
},
initialize: function(){
console.log("Music is the answer");
}
});
var Album = Backbone.Collection.extend({
model: Song
});
var song1 = new Song({ name: "How Bizarre", artist: "OMC" });
var song2 = new Song({ name: "Sexual Healing", artist: "Marvin Gaye" });
var song3 = new Song({ name: "Talk It Over In Bed", artist: "OMC" });
var myAlbum = new Album([ song1, song2, song3]);
console.log( myAlbum.models ); // [song1, song2, song3]
The problem is - this doesn't give me model names in the console:
console.log( myAlbum.models ); // [song1, song2, song3]
instead I get [child, child, child, child] - how do I get the actual names?
You need to pluck the name attribute.
myAlbum.pluck('name');
There is no way to get an array like this:
['song1', 'song2', 'song3']
because names of variables are not available in program logic.
Update
When the tutorial writes this:
console.log( myAlbum.models ); // [song1, song2, song3]
It means that the array models is the same as if you were to write [song1, song2, song3], not as if you were to write ['song1', 'song2', 'song3']. The quotes are the differentiating factor.
Related
My model
app.Item = Backbone.Model.extend({
defaults: {
title: '',
checked: false,
price: 0
}
});
Collection
app.ItemCollection = Backbone.Collection.extend({
model: app.Item,
localStorage: new Store('itaaatems')
});
I create a simple collection that has the model 'Item'.
app.itemCollection = new app.ItemCollection([
new app.Item({title: "webb dev", checked: true, price: 100}),
new app.Item({title: "drawing", price: 200}),
new app.Item({title: "corn harvesting", price: 750}),
new app.Item({title: "pen spinning", price: 50}),
new app.Item({title: "pen spiddnning", price: 50}),
new app.Item({title: "shark riding", price: 2000})
]);
I save each of them and see the success callback.
app.itemCollection.each(function (item){
item.save(null, {success: function () {
console.log('good');
}
});
});
Everything looks good as I see each item as a model
app.itemCollection.each(function (item){
console.log(item);
});
But when I try to delete them and for some reason after deleting the 3rd item, it hits a undefined. The 4th item is not defined for some reason while the first 3 I get success callbacks.
app.itemCollection.each(function (item){
item.destroy({success: function (model, response) {
console.log(response);
}
});
});
The problem is that you're iterating over an array and modifying it at the same time. Your app.itemCollection.each is little more than:
for(var i = 0; i < app.itemCollection.models.length; ++i)
app.itemCollection.models[i].destroy({ ... });
in disguise and each destroy call will change the app.itemCollection.models array behind your back. If you keep an eye on the collection as you're deleting things:
app.itemCollection.each(function(item) {
console.log(app.itemCollection.toJSON());
item.destroy({ ... });
});
you should see the iteration appear to skip items.
You could iterate backwards and use Collection#at and a for-loop:
for(i = app.itemCollection.length - 1; i >= 0; --i)
app.itemCollection.at(i).destroy({ ... });
or use toArray to get a copy of the underlying array of models and iterate over that:
app.itemCollection.toArray().forEach(function(item) {
item.destroy({ ... });
});
I'm trying to get some data from the node server, which works fine, but when I try to GET data via the Backbone fetch (or sync), the request fails. I noticed that, for some reason, actual request is wrong: 'GET http://localhost:3000/socket.io/1/' where it should be 'GET http://localhost:3000/cars', since '/cars' is the value of the URL field that Backbone uses by convention for these operations. These are the relevant modules:
var Backbone = require("backbone");
var Car = require('models/car');
var Cars = Backbone.Collection.extend ({
model: Car,
url: '/cars',
// Unselect all Car Cards
resetSelected: function() {
for (var i=1; i<=this.length; ++i) {
var carcard=this.get(i);
carcard.set({"selected": false});
console.log(carcard.attributes.name + ' unselected');
}
},
// Select a specific model from the collection
selectByID: function(id) {
this.resetSelected();
var carcard = this.get(id);
carcard.set({"selected": true});
console.log(carcard.attributes.name + " selected");
return carcard.attributes.id;
}
});
module.exports = Cars;
And a model:
var Backbone = require("backbone");
var Car = Backbone.Model.extend({
defaults: {
year: 2011,
brand: "Brand",
model: "Model",
name: "Car Name",
pictureFle: "img/car.jpg",
kmTraveled: 0,
litresSpent: 0,
selected: false
},
});
module.exports = Car;
I tried to populate the collection like this:
var cars = new Cars();
cars.fetch();
but, as I explained, failed. Any ideas what the problem could be?
I have a Backbone App with 3 model which have nested collections:
Models Structure:
Layout extends Backbone.Model
-> sections: new Sections extends Backbone.Collection
Section extends Backbone.Model
-> rows: new Rows extends Backbone.Collection
Now if I have two section model in layout and I go and add row model to one of the Section.rows collection, it is adding it to both sections.
BTW, I am adding it from a view on an event.
Thanks in Advance.
got a workaround. I could reproduce your workflow by adding defaults property to my models.
like this:
var Section = Backbone.Model.extend({
defaults: {
rows: new Rows
}
});
var Layout = Backbone.Model.extend({
defaults: {
sections: new Sections
}
});
then really, if i add new row to rows to one of my section its appear to adding to all sections rows collection. So i do this (rude example):
var Row = Backbone.Model.extend({
defaults: {
rowData: 0
}
});
var Rows = Backbone.Collection.extend({
model: Row
});
var Section = Backbone.Model.extend({
//defaults: {
// rows: new Rows
//}
});
var Sections = Backbone.Collection.extend({
model: Section
});
var Layout = Backbone.Model.extend({
//defaults: {
// sections: new Sections
//}
});
var LayoutView = Backbone.View.extend({
});
var lView = new LayoutView({ model: new Layout });
lView.model.set('sections',new Sections());
var sections = lView.model.get('sections');
sections.add({id: 1, name: 's1',rows: new Rows() });
sections.add({id: 2, name: 's2',rows: new Rows() })
var rows = sections.get(1).get('rows');
rows.add({id:'r1',rowsData: 10});
console.log(lView.model.toJSON());
#aleha you are right the issue is of the default attribute settings in Model. As they share the same memoery space(javascript: pass by reference not by value ).
So what I did is in the initialize function
initialize: function() {
this.set( 'rows', new Rows() );
}
So, no need to do it like you are doing above:
sections.add({id: 1, name: 's1',rows: new Rows() });
Hence resolved and automate :)
Thanks for the help though.
im learning BackboneJs using the documentation and a book called "Beginning backbone".
But I have been stuck at the sorting collections part for hours.
Also tried to research but I find the results complicated =/
I know I have to use the comparator, as shown in the documentation but I don't understand how to apply it to the current code syntax-wise
http://backbonejs.org/#Collection-comparator
var Book = Backbone.Model.extend({
defaults:
{
title: "default title",
author: "default author",
pages: 20
},
comparator: function(item)
{
//sort by title
return item.get('title');
}
});
var book1 = new Book({ title:"Book of wonders",author:"author1",pages:1 });
var book2 = new Book({ title:"Zelda",author:"author2",pages:2 });
var book3 = new Book({ title: "Drake's out", author: "author3",pages:3});
var book4 = new Book({ title: "AutoCad",author: "author4",pages: 4});
var Library = Backbone.Collection.extend({
model: Book
});
var library = new Library([book1,book2]);
library.add([book3,book4]);
library.forEach(function(model){
console.log('Book is called '+model.get("title"));
});
console.log('Library contains '+library.length+' books');
This is a working solution, it will sort everything by title.
to sort it by anything else just change the parameter of the get function inside the comparator function
var Book = Backbone.Model.extend({
defaults:
{
title: "default title",
author: "default author",
pages: 20
}
});
var book1 = new Book({ title:"Book of wonders",author:"author1",pages:1 });
var book2 = new Book({ title:"Zelda",author:"author2",pages:2 });
var book3 = new Book({ title: "Drake's out", author: "author3",pages:3});
var book4 = new Book({ title: "AutoCad",author: "author4",pages: 4});
var Library = Backbone.Collection.extend({
model: Book,
initialize: function()
{
console.log("new collection");
},
comparator: function(a,b)
{
//sort by title
return a.get('title') < b.get('title') ? -1 : 1;
}
});
var library = new Library([book1,book2]);
library.add([book3,book4]);
library.sort();
library.forEach(function(model){
console.log('Book is called '+model.get("title"));
});
console.log('Library contains '+library.length+' books');
I have this model defaults:
test.Models.ItemModel = Backbone.Model.extend({
defaults: {
name: 'an item',
units: []
},
Which I then use the following code to set the Model:
addUnit: function(e){
if(e.keyCode == 13){
this.model.set({ 'units' : this.model.get('units').push($('#addUnit').val()) },
{success: function(){
this.render();
}}
);
}
},
However, it never seems to get added to the Model array, am I doing things right here??
The problem is that you're assuming the the push method is returning the whole array; instead, as stated here, the push method
Returns the new length property of the object upon which the method was called.
So, you need to push the element into the array before you set it to the model :
var _units = this.model.get('units');
_units.push($('#addUnit').val());
this.model.set({ 'units' : _units });
Careful though, this will modify anything else that points to this array, so if you do this, for example:
var myArray = [1,2,3]
this.model.set({units: myArray})
var _units = this.model.get('units')
_units.push(4)
this.model.set({ 'units' : _units })
myArray == this.model.get('units') // holy moly, they're the same :(
If you want to avoid this, or still want to use a single line of code for that, you could use array's concat method:
this.model.set({
'units' : this.model.get('units').concat($('#addUnit').val())
});