Filter backbone collection by attribute value - backbone.js

I have a defined model and a collection:
var Box = Backbone.Model.extend({
defaults: {
x: 0,
y: 0,
w: 1,
h: 1,
color: "black"
}
});
var Boxes = Backbone.Collection.extend({
model: Box
});
When the collection is populated with the models, I need a new Boxes collection made out of Box models that have a specific color attribute contained in the complete collection, I do it this way:
var sorted = boxes.groupBy(function(box) {
return box.get("color");
});
var red_boxes = _.first(_.values(_.pick(sorted, "red")));
var red_collection = new Boxes;
red_boxes.each(function(box){
red_collection.add(box);
});
console.log(red_collection);
This works, but I find it a bit complicated and unefficient. Is there a way of doing this same thing in a more simple way?
Here is the code I described: http://jsfiddle.net/HB88W/1/

I like returning a new instance of the collection. This makes these filtering methods chainable (boxes.byColor("red").bySize("L"), for example).
var Boxes = Backbone.Collection.extend({
model: Box,
byColor: function (color) {
filtered = this.filter(function (box) {
return box.get("color") === color;
});
return new Boxes(filtered);
}
});
var red_boxes = boxes.byColor("red")

See http://backbonejs.org/#Collection-where
var red_boxes = boxes.where({color: "red"});
var red_collection = new Boxes(red_boxes);

Related

Backbone fetch (or sync) doesn't look up right url

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?

Backbone Collection Issue

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.

BackboneJS How to merge collections

I asked this before BackboneJS Display multiple collections in one <ul>-Element but I can't get it to work and I'm starting getting really desperate so
how can I merge these 3 collections and display them in the same <ul>?
define(['app','backbone','modules/artistInstagram', 'modules/artistTwitter',
'modules/artistFacebook'
], function (App, Backbone, ArtistInstagram, ArtistTwitter, ArtistFacebook) {
var ArtistSocialMedia = App.module();
ArtistSocialMedia.View = Backbone.View.extend({
tagName: 'ul',
id: 'suptiles',
beforeRender: function(){
var artistinstagramCollection = new ArtistInstagram.ArtistInstagramCollection();
artistinstagramCollection.artist_id = this.artist_id;
this.insertView('.socialMedia', new ArtistInstagram.View({collection: artistinstagramCollection}));
artistinstagramCollection.fetch();
var artisttwitterCollection = new ArtistTwitter.ArtistTwitterCollection();
artisttwitterCollection.artist_id = this.artist_id;
this.insertView('.socialMedia', new ArtistTwitter.View({collection: artisttwitterCollection}));
artisttwitterCollection.fetch();
var artistfacebookCollection = new ArtistFacebook.ArtistFacebookCollection();
artistfacebookCollection.artist_id = this.artist_id;
this.insertView('.socialMedia', new ArtistFacebook.View({collection: artistfacebookCollection}));
artistfacebookCollection.fetch();
}
});
return ArtistSocialMedia;
});
Right now, it clearly creates 3 views but I want to merge them into one collection. Please help!
Thanks in advance...
Don't overthink it - since you're defining an element with dynamic content, it should be its own View. It's an unordered list, so the tag name must be <ul>. All you're doing is filling in the <li>'s, so the template isn't very complicated.
var collection1 = new WhateverCollection();
var collection2 = new WhateverCollection();
var collection3 = new WhateverCollection();
var ListView = Backbone.View.extend({
tagName: 'ul',
render: function(){
// define template
var templateStr = '<% _.each(collection,function(model){ %>\
<li><%- model.name %></li>\
<% }); %>';
// convert to function
var template = _.template(templateStr);
// for learning purposes, render each one individually
var htmlFromFirst = template({ collection: collection1.toJSON() });
var htmlFromSecond = template({ collection: collection2.toJSON() });
var htmlFromThird = template({ collection: collection3.toJSON() });
// set the html
this.$el.html( htmlFromFirst + htmlFromSecond + htmlFromThird );
return this;
}
});

Knockback: Remove item from an observable collection

Given an observable collection in Knockback, how do I remove an item from the underlying collection in response to a knockout.js click event?
If I'm right, a would say you want delete some item from the collection by clicking a button.
So we have the kb view:
var viewModel = kb.ViewModel.extend({
constructor: function(model, options) {
var self = this
this.delete= function(){
self.coll.delete(self)
}
this.coll = options.coll
this.name = kb.Observable(model, {key: 'name'})
}
});
var yourCollection = new Backbone.Collection();
var yourModel = new Backbone.Model({name: 'Stefan'});
var yourKBView = new viewModel (yourModel, {coll: yourCollection});
This is a simple way to store some nested information.
When you will do this automatic when a model is add in the collection you can override the create function of the view like this.
var collectionViewModel = kb.ViewModel.extend({
constructor: function(collection, options) {
var self = this
this.coll= kb.collectionObservable(collection, {
/**
* Calls by adding a model to the collcetion
* #param model -
* #param options -
*
*/
create: function(model, options){
var options = options || {}
options.coll = self
return new viewModel(model,options)
}
});
}
});

EXTJS 3.3.3 Grid

I am developing a checkbox grid list with pagination using the EXTJS grid. I need to remember the selected record when the page navigation is performed.
Details:
1) Go to page:1 and selected rows 1,2 and 3.
2) Now navigate to page:2
3) Come back to page:1
4) The rows 1,2 and 3 which are already selected should be shown as selected
Is there is any api in grid which handles this kind of function?
Thanks in advance.
Thanks for your responses. I have achieved my design by implementind a plugin for grid. The plugin looks as,
Ext.namespace('Ext.ux.plugins');
Ext.ux.plugins.CheckBoxMemory = Ext.extend(Object,
{
constructor: function(config)
{
if (!config)
config = {};
this.prefix = 'id_';
this.items = {};
this.idProperty = config.idProperty || 'id';
},
init: function(grid)
{
this.view = grid.getView()
this.store = grid.getStore();
this.sm = grid.getSelectionModel();
this.sm.on('rowselect', this.onSelect, this);
this.sm.on('rowdeselect', this.onDeselect, this);
this.store.on('clear', this.onClear, this);
this.view.on('refresh', this.restoreState, this);
},
onSelect: function(sm, idx, rec)
{
this.items[this.getId(rec)] = true;
},
onDeselect: function(sm, idx, rec)
{
delete this.items[this.getId(rec)];
},
restoreState: function()
{
var i = 0;
var sel = [];
this.store.each(function(rec)
{
var id = this.getId(rec);
if (this.items[id] === true)
sel.push(i);
++i;
}, this);
if (sel.length > 0)
this.sm.selectRows(sel);
},
onClear: function()
{
var sel = [];
this.items = {};
},
getId: function(rec)
{
return rec.get(this.idProperty);
}
});
This plugin was called from gird as,
Ext.grid.Gridpanel({
store: 'someStore',
plugins: [new Ext.ux.plugins.CheckBoxMemory({idProperty: "recordID"})]
});
Hope this helps some one.
I don't think there is. You;d need to store IDs of selected records in some separate store/array and use it to re-apply selections when page is changed.
You could put a MixedCollection Object at the global scope to keep track of these records. This will allow you to store global settings of different object types.

Resources