For Loop over Backbone Collection - javascript

Fairly new to backbone, so this is a really basic question. I have a Backbone collection passed into a function and I can prove that it has been passed and that the models in the collection have ids.
Here's how I'm setting the ids -
convertToMapObjects: (results) =>
objectList = new ObjectList()
results.each(result)->
testObj = new TestObject()
testObj.set
id = result.get("id")
objectList.add(testObj)
And in another function ( accessed through making the model trigger an event) -
getIds: (objects) =>
ids = (object.id for object in objects)
I think the issue may be because of how I'm iterating through the collection because when I tried doing
for object in objects
console.log(object)
I saw two undefineds. Is this correct? If so, why can't I use a for loop to go through a backbone collection? Also, is there a way I could do so?

A Backbone collection is not an array so for ... in won't produce the results you're expecting. You want to look at the collection's models property if you want to use a simple loop.
However, Backbone collections have various Underscore methods mixed in:
Underscore Methods (28)
Backbone proxies to Underscore.js to provide 28 iteration functions on Backbone.Collection. They aren't all documented here, but you can take a look at the Underscore documentation for the full details…
forEach (each)
...
So you can use map or pluck if you'd like to avoid accessing the models property:
ids = objects.map (m) -> m.id
ids = objects.pluck 'id'
The pluck method is, more or less, just a special case of map but collections implement a native version rather than using the Underscore version so that they can pluck model attributes rather than simple object properties.

You want to loop over the models property of the collection, not the collection object itself.

for object in object.models
This will give you a model in the collection

Related

What is the data structure of a collection/ordered set in Backbone?

The Backbone docs says this -
Collections are ordered sets of models.
But what exactly is an ordered set? I know it's an object but what I don't understand the data structure because it has keys like an object-
Object.keys(exampleCollection
//returns ["length", "models", "_byId", "currentSort", "fetched", "_listenerId", "_events", "comparator"]
but you can call array functions on it like map-
exampleCollection.map(function (mod) {console.log(mod)})
//displays 3 models
The underlying data structure is an array. Most of the Backbone.Collection methods operate on this.models which is an array. The great thing about Backbone is that it's easy to open it up and take a look at what's under the hood -- especially with their annotated source.

Can we use underscore's "where" to filter collection by CID

I am simply wondering if we can only filter Backbone collections by attributes, but not by other properties such as CID
is this correct:
_.where(collection,{cid:'xyz'}) // filters by cid property?
_.where(collection,{attributes:{firstName:'foo'}}) // filters by attributes.firstName?
I hope someone can understand my confusion about how to use where to filter on nested properties.
Can someone please explain is if it is possible to filter by a top level property like CID or if Backbone collections are configured to just filter by attributes.
Normally you'd use _.where to search an array of objects for matching properties. So saying _.where(collection, ...) doesn't make a lot of sense, you'd want to search the collection's models array:
var a = _.where(collection.models, { cid: 'xyz' })
That will do more or less the same thing as:
var a = [ ], i;
for(i = 0; i < collection.models.length; ++i)
if(collection.models[i].cid === 'xyz')
a.push(collection.models[i])
_.where doesn't know about the special structure of a Backbone collection so it doesn't know that it should be looking at collection.models or that there are attributes inside the models unless you tell it. Since cid is a property of models rather than an attribute, the above _.where works.
If you want to search the model attributes then you'd want to use the Underscore methods that are mixed into collections as they are adjusted to look at the collection's models or the special Collection#where that knows about the attributes object inside models. So if you wanted to look for a firstName attribute then you'd say:
collection.where({ firstName: 'foo' })
There's no support for searching nested objects out of the box. However, all the wheres are just wrappers for _.filter so you can write your own predicate function that does whatever you want:
collection.filter(function(model) {
// Do whatever you want to model, return true if you like
// it and false otherwise.
});
For the most part you should try to ignore the Backbone.Collection#models and Backbone.Model#attributes properties and use the various methods instead. There's usually a better way to deal with models and attributes that will be sure to take care of any internal bookkeeping.

Meteor: Create a new collection from one attribute of an existing collection

In my Meteor app, I already have a collection fullList = new Mongo.Collection('fullList'); that is an array of objects, and each object has several attributes, such as Color, Factor, and Tot.
I want to create a new collection - or at least just a new array - that is, an array of all of the Tot values. The pseudo-code would be something like newList = fullList.Color, if that makes sense.
I know how to display one attribute in html using {{Color}}, but I can't seem to do anything with it in JavaScript.
In case it's relevant, the reason I want this array is I'd like to use D3.js to represent that data.
It sounds like your collection is a set of documents (in Mongo terminology), with each document being a serialised object, rather than actually a single-document collection that stores an array. In that case, you should be able to use the built-in map function on your collection cursor. Documentation here:
http://docs.meteor.com/#/full/map
This would look something like (using only the document argument in the callback):
fullList = new Mongo.Collection('fullList');
newlist = fullList.find().map(function(document) {
return document.Tot;
});
map() will iterate over all the documents in the collection - as no arguments are passed to find() - and for each document add an item to an array (assigned to newList) that is the value returned by the callback function, in this case Tot.

Listing instances of a Model in Backbone application

In my Backbone application I have a Model. Is there a way of getting all instances of this Model in the app if not all of the instances belong to same Collection? Some of the instances might not belong to any Collection at all.
WHY do I need to do this?
I have a namespaced models (let's say Order.Models.Entry). This is the model of the instances I am talking about. There are some collections like Order.Models.Entries that contain instances of Order.Models.Entry type. But instances get to this collection only when they are selected (with a certain attribute). Before being selected the models are just… well… models.
UPDATE
Obviously I could load every model I create to some allModels collection as it has been suggested in the comments. But the question is not really about a workaround but about exact lookup. The reason why I would like to avoid adding models to an uber-collection is that most of the models will be added to different collections anyway and I just wanted to avoid creating dummy collection for just tracking purpose.
No. There are a couple of good design reasons why you shouldn't be doing it. (encapsulation, not polluting the global scope, etc...)
If you still wish to have this solution you could just maintain a Gloabl list and have your Backbone.Model insert itself into this list, here is a quick solution:
var allMyModels = [] ;
var MyModel = Backbone.Model.extend({
initialize:function(){
allMyModels.push(this);
// Some more code here
},
// also if you wish you need to remove self on close delete function
});
var x = new MyModel();
var y = new MyModel();
in the end of this code, allMyModels will have both models
Why don't you create a Collection (we'll call it allModels) and each time a model is created, do: allModels.add(model). That way, you can access the models, and if you destroy one it will remove itself from the collection.

How does map work with a Backbone collection?

Goal: I am trying to create a case insensitive search that goes through my collection and tries to match the user query against model's name attribute. Right now if I want to find a specific model, the search query must be exact.
It seems there is no easy way to do something so simple in Backbone, not out of the box. The function map came to mind. What if I could go through the entire collection and change model's name attribute to lower case, then change user query to lower case as well and voila!
But the problem is I have no idea how to use Backbone Collection and map function. There is no documentation on map in Backbone docs, other than a link that leads you to underscore documentation with a super primitive example code using an array of three numbers.
This does not work...why?
this.collection.map(function(model) {
return model.get('name').toLowerCase();
});
Actually, all of underscore's collection methods are proxied on Backbone.Collection objects. when you do a collection.map(... it returns an array of objects returned by the mapped function. The solution presented by raina77ow does not work since a Backbone.Collection is not an array and assigning the result of the map to this.collection will destroy the collection itself.
If you want to filter a collection, I would recommend using the filter method. ( I assume you are working from a Backbone.View:
var filter = this.$('#search-field').val(),
filteredModels = this.collection.filter( function( model ) {
return model.get('name').toLowerCase() === filter;
};
this.collection.reset( filteredModels );
Note that any of underscore's proxied methods on collections will return an array of models. If you then want to use them, you can reset the collection with these models or, equivalently, set the collection's models attribute to the filtered results: this.collection.models = filteredModels. The first form has the advantage of triggering a reset event on the collection to which you can listen to and, for example re-render your view.

Categories

Resources