Backbone collection inside model - javascript

I'm new to backbone and I wonder if there is a way to save previous models in a collection as an attribute of the model itself. For example,
var history = Backbone.Collection.extend({});
var myModel = Backbone.Model.extend({
defaults: {
id: '',
name: '',
history: history //history is a collection of myModel
},
//override setter so when set method is called, it will save the previous model inside history collection.
})

This would be ephemeral history
var myModel = Backbone.Model.extend({
defaults:{
id:''
},
constructor: function(){
this.history = new Backbone.Collection();
},
set: function(){
var args = Array.prototype.slice.call(arguments);
this.history.add(this.toJSON());
return Backbone.Model.prototype.set.apply(this, args);
}
});

Related

Model is not a constructor-Backbone

I have created a model and collection for a json to be fetched as shown here.When i'm instantiating in the service i'm getting error that my model is not a constructor.My model uses collection of models for storing time/value pairs.
ServiceMonitoringModel.js
define(function(require) {
'use strict';
var _ = require('underscore');
var Backbone = require('backbone');
var ServiceMonitoringCollection=require('./ServiceMonitoringCollection');
var ServiceMonitoringModel = Backbone.Model.extend({
modelNAme: 'ServiceMonitoringModel',
idAttribute: 'id',
defaults: {
// todo
content_type: '',
content_graph: {
capacity: null,
performance: {
memory: new ServiceMonitoringCollection(),
cpu: new ServiceMonitoringCollection()
}
}
},
initialize: function() {
//todo
},
validate: function(attributes) {
},
parse: function(response) {
return {
content_type: response.content_type,
content_graph: {
capacity:this.getDeepJsonValue(response, 'capacity'),
performance: {
memory: new ServiceMonitoringCollection(this.getDeepJsonValue(response, 'memory'),{parse:true}),
cpu: new ServiceMonitoringCollection(this.getDeepJsonValue(response, 'cpu'),{parse:true})
}
}
};
}
});
return ServiceMonitoringModel;
});
Service.js
...
var ServiceMonitoringModel=require('common/model/server/ServiceMonitoringModel');
var ServiceMonitoringModel = new ServiceMonitoringModel();
Your problem is:
var ServiceMonitoringModel = new ServiceMonitoringModel();
You are assigning a value to your Model definition. Try:
var serviceMonitoringModel = new ServiceMonitoringModel();
Notice the lowercase s

Backbone update model if its already exist in collection

I'm trying to implement basic cart on backbone.js I'm completely new in it.itemsListView adds object to cartCollection. Problem is that when model is added in collection I want to increment this model quantity attribute if this model already exist in cartCollection.
var Phone = Backbone.Model.extend({});
var PhonesCollection = Backbone.Collection.extend({
model: Phone
});
var itemListView = Backbone.View.extend({
collection: null,
_template: _.template($('#listTemplate').html()),
el: $('#phonesDiv'),
events: {
'click .buyButton': '_addToCart'
},
initialize: function () {
'use strict';
this.render();
},
render: function () {
'use strict';
var rendTemplate = this._template({items: this.collection.toJSON()});
this.$el.html(rendTemplate);
return this;
},
_addToCart: function (e) {
'use strict';
var buttonId = $(e.currentTarget).attr('id');
var result = this.collection.findWhere({id: buttonId});
var purchase = {
id: result.attributes.id,
name: result.attributes.name,
price: result.attributes.price
};
cartcollection.add(new cartModel({
id: buttonId,
item: _.pick(purchase, 'id', 'name', 'price'),
itemTotalPrice: purchase.price
}));
console.log(cartcollection);
}
});
cartModel and cartCollection:
var cartModel = Backbone.Model.extend({
defaults: {
id: null,
item: {
id: null,
name: null,
price: null
},
itemTotalPrice: 0,
quantity: 1
}
});
var cartCollection = Backbone.Collection.extend({
model: cartModel,
defaults:{
totalQuantity: 0,
totalPrice: 0
}
You can do this by adding a method to your collection class. Here's one way to do it, with a method I'm calling addToCart:
var cartModel = Backbone.Model.extend({
defaults: {
quantity: 0
}
});
var cartCollection = Backbone.Collection.extend({
model: cartModel,
addToCart: function (model) {
this.add(model);
var q = model.get('quantity');
model.set('quantity', q + 1);
}
});
When you call a Backbone collection's add method, if the model you use as an argument is already in the collection, it will not be added again. Then, you can just increment the model's quantity manually.
The code below shows how this would work; you can play with it in JSBin.
var m1 = new cartModel({ name: 'm1' });
var m2 = new cartModel({ name: 'm2' });
var cart = new cartCollection();
cart.addToCart(m1);
cart.addToCart(m1);
cart.addToCart(m2);
console.log('cart length:', cart.length); // 2
console.log('m1 quantity:', m1.get('quantity')); // 2
console.log('m2 quantity:', m2.get('quantity')); // 1
$(function() {
var cartModel = Backbone.Model.extend({
defaults: {
id: null,
item: "",
quantity: 1
}
});
var cartCollection = Backbone.Collection.extend({
model: cartModel
});
// sample data
var data = [{id: 1, item:"testA"}, {id: 2, "item":"testB"}, {id: 1, "item":"testA"}, {id: 1, "item":"testA"}]
var cart = new cartCollection();
for(i in data){
var item = data[i];
// check if item already exists in collection
var model = cart.get(item.id);
if(model){
// increment model's quantity by 1
var quantity = model.get("quantity");
model.set("quantity", ++quantity);
// remove the model from collection and add updated model
cart.remove(item.id);
cart.add(model);
}else{
// if model doesn't exist in collection
// simple add it to collection
cart.add(item);
}
}
console.log(cart);
});
<script src="http://getfirebug.com/firebug-lite-debug.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.2.1/backbone-min.js"></script>

Backbone collection sortBy

I make my first backbone app and get some problems with collection sorting.
After using this
var SortedFriends = MyFriends.sortBy(function(friend) {
return friend.get("uid");
});
console.log(SortedFriends) show that SortedFriends contains sorted models, but when i try to use collection functions like 'SortedFriends.each' or 'SortedFriends.at' it make error:
TypeError: SortedFriends.each is not a function.
Code:
var Friend = Backbone.Model.extend({});
var Friends = Backbone.Collection.extend({
model: Friend,
});
var MyFriends = new Friends();
MyFriends.reset(<?=$friends?>);
var FriendView = Backbone.View.extend({
initialize: function(){
model:Friend
},
tagName: "tr",
template: _.template($('#item-template').html()),
className: "document-row",
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
var SortedFriends = MyFriends.sortBy(function(friend) {
return friend.get("uid");
});
var addOne = function(element){
var view = new FriendView({model: element});
$("#friends").append(view.render().el);
}
console.log(JSON.stringify(SortedFriends));
SortedFriends.each(function(friend){
var view = new FriendView({model: friend});
$("#friends").append(view.render().el);
});
If youre using backbone collections then youre probably better off using the comparator rather than collection methods
http://backbonejs.org/#Collection-comparator
When youre ready to sort your collection:
MyFriends.comparator = function(friend){
return friend.get("uid");
});
MyFriends.sort();
OR if you want to keep the order of the unsorted collection then you will need to clone it first
http://backbonejs.org/#Collection-clone
var SortedFriends = MyFriends.clone();
SortedFriends.comparator = function(friend){
return friend.get("uid");
});
SortedFriends.sort();
I'm not sure if it's a bug or a feature of Backbone's adaptation of sortBy, but apparently it returns an array, not an Underscore collection.
One workaround is to wrap the whole thing in _( ... ), which tells Underscore to wrap the array back into a collection:
var SortedFriends = _(MyFriends.sortBy(function(friend) {
return friend.get("uid");
}));
Edit
Most of the Underscore methods in Backbone seem to be chainable (replace sortBy with reject, for example, and it runs). Looking at the Backbone source where they wire up the Underscore proxies, it seems that sortBy is treated differently. I can't understand why they do it this way ...
var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
'tail', 'drop', 'last', 'without', 'indexOf', 'shuffle', 'lastIndexOf',
'isEmpty', 'chain'];
_.each(methods, function(method) {
Collection.prototype[method] = function() {
var args = slice.call(arguments);
args.unshift(this.models);
return _[method].apply(_, args);
};
});
var attributeMethods = ['groupBy', 'countBy', 'sortBy'];
_.each(attributeMethods, function(method) {
Collection.prototype[method] = function(value, context) {
var iterator = _.isFunction(value) ? value : function(model) {
return model.get(value);
};
return _[method](this.models, iterator, context);
};

Backbone - Possible to get the collection from a model

I'm wondering if there's a way to get a reference to a collection from one of its models. For instance, if any of the people in the collection below are somehow aware of belonging to a collection, or multiple collections. Fiddle
(function() {
window.App = {
Models: {},
Views: {},
Collections: {}
};
App.Models.Person = Backbone.Model.extend({
defaults: {
name: 'John',
phone: '555-555-5555'
}
});
App.Views.Person = Backbone.View.extend({
tagName: 'li',
template: _.template("<%= name %> -- <%= phone %>"),
render: function(){
var template = this.template( this.model.toJSON() );
this.$el.html( template );
return this;
}
});
App.Collections.People = Backbone.Collection.extend({
model: App.Models.Person
});
App.Views.People = Backbone.View.extend({
tagName: 'ul',
add: function(person){
var personView = new App.Views.Person({ model: person });
this.$el.append( personView.render().el );
return this;
},
render: function() {
this.collection.each(this.add, this);
return this;
}
});
})();
var peeps = [ { name: 'Mary' }, { name: 'David' }, { name: 'Tiffany' } ];
var people = new App.Collections.People(peeps);
var peopleView = new App.Views.People({ collection: people });
peopleView.render().$el.appendTo('body');
Each model has a property called collection. In your fiddle, adding console.log(people.models[0].collection) will print out the collection.
Looking through the source code, it looks like this is what's used to do things like remove a model from a collection when the model's destroy() method is called.
Update: see this updated fiddle which creates three person models and two collections. It prints them to the console. It looks like model.collection only refers to the first collection the person was added to, not the second.

Why are my Backbone Models nested strangely within a Collection, requiring drilling down to access methods/properties?

I've got a Collection and a Model, both using attributes/options to augment them with additional capabilities. Here's the Model (LoadRouteGroup):
return Backbone.Model.extend({
initialize: function () {
console.log(this);
},
fetchf: function () {
console.log("FETCH");
}
});
And the Collection (LoadRouteGroups):
return Backbone.Collection.extend({
constructUrl: function(options) {
if (options.groupingType === "facility") {
// TODO: new endpoint: /api/v1/loadroutes?grouping=facility
this.url = clawConfig.endpoints.webApiRootUrl + "/api/loads/facilities";
}
else {
this.url = clawConfig.endpoints.webApiRootUrl + "/api/v1/loadroutes";
}
},
initialize: function (models, options) {
options || (options = {});
this.constructUrl(options);
console.log(this);
}
});
They're instantiated as such:
var loadRouteGroup = new LoadRouteGroup({
entityType: "facility"
});
// WORKS
loadRouteGroup.fetchf();
// assign groupingType option to collection to denote which URL to use
var loadRouteGroups = new LoadRouteGroups({
model: loadRouteGroup
}, {
groupingType: "facility"
});
var firstGroup = loadRouteGroups.at(0);
// DOESN'T WORK
firstGroup.fetchf();
// WORKS
firstGroup.attributes.model.fetchf();
I would expect that call to firstGroup.fetchf() to work... but it doesn't. Instead, I have to weirdly drill down and use firstGroup.attributes.model.fetchf() in order to access the method.
What's going on here? This would seem straightforward to me, but I can't for the life of me figure out what's wrong with the relationship between my Collection and Model.
The collection definition should include the model type:
return Backbone.Collection.extend({
// ....
model: LoadRouteGroup
});
When initializing the collection, pass in an array of models:
var loadRouteGroup = new LoadRouteGroup({
entityType: "facility"
});
var loadRouteGroups = new LoadRouteGroups([loadRouteGroup], {
groupingType: "facility"
});
Specify the model when you extend the collection instead of when you instantiate.

Categories

Resources