How to get a filtered collection - javascript

Lets suppose I have a big collection and I want to use a subset of this big collection for different view.
I tried the following code but it does not work because the filtered collection actually is a new one and it does not refer to the BigCollection instance.
My question is:
how can I get a collection which is a subset of BigCollection instance?
Here is my code. Please see the comments for more info:
// bigCollection.js
var BigCollection = Backbone.Collection.extend({
storageName: 'myCollectionStorage',
// some code
});
// firstView.js
var firstView = Marionette.CompositeView.extend({
initialize: function(){
var filtered = bigCollection.where({type: 'todo'});
this.collection = new Backbone.Collection(filtered);
// the issue is about the fact
// this.collection does not refer to bigCollection
// but it is a new one so when I save the data
// it does not save on localStorage.myCollectionStorage
}
});

Use BigCollection to make filtered collection, like this :
// firstView.js
var firstView = Marionette.CompositeView.extend({
initialize: function(){
var filtered = bigCollection.where({type: 'todo'});
this.collection = new BigCollection(filtered);
// now, it will save on localStorage.myCollectionStorage
}
});

You could just save your original models in a variable inside your collection so you can restore them after you de-apply the filter, like this:
// bigCollection.js
var BigCollection = Backbone.Collection.extend({
storageName: 'myCollectionStorage',
// some code
});
// firstView.js
var firstView = Marionette.CompositeView.extend({
initialize: function(){
bigCollection.original_models = bigCollection.models;
bigCollection.models = bigCollection.where({type: 'todo'});
}
});
And then you can restore them when you toggle the filter:
bigCollection.models = bigCollection.original_models;

Related

How to send collection to another view?

Is there anyway to send backbone collection to another view without listenTo methods, to send it like an array or something else.
Im doing the fetch in the initialize function and then putting the collection in my array is that bad?
this.userModels = [];
this.collectionUser = new app.types.Users();
this.collectionUser.fetch();
this.userModels.push(this.collectionUser);
Im trying to send it like an array but on refreshing my web page sometimes im getting this
this.options child {
length: 15,
models: Array[15],
_byId: Object,
_listenId: "l4",
_events: Object…
}
and sometime getting with zero values
this.options child {
length: 0,
models: Array[0],
_byId: Object,
_listenId: "l4",
_events: Object…
}
So i wanna send my collection without listenTo method if it's possible.
First view:
app.types.FirstView = Backbone.View.extend({
initialize: function() {
this.collectionUser = new app.types.Users();
this.collectionUser.fetch();
};
sendCollection: function() {
var secondView = new app.types.SecondView({
collection: this.collectionUser
});
}
});
Second view:
app.types.SecondView = Backbone.View.extend({
initialize: function(options) {
this.collection = options.collection;
// so i want to get this.collectionUser here without listenTo
// method and without fetch here is that possible ? I said
// sometimes i get it sometimes not when i refersh my web page
// when i render it first time.
};
});
Yes you can send everything with js and use initialize for that view.
In your view you need to declare initialize function like this.
var someView = Backbone.View.extend({
template: _.template('some html file'),
initialize: function(options){
this.collection = options.collection
},
events: {
'click .someclass': 'doSomthing',
'click #someId': 'doSomthingElse'
},
doSomthing: function(event){
event.preventDefault();
var that = this;
that.collection.fetch({
success: function(){
that.$('element').append(that.collection);
}
});
},
render: function(){
var that = this;
that.$el.html(that.template);
return this;
}
});
And when u make new instance of your view need pass your collection as argument.
this.collectionUser = new app.types.Users();
this.view = new someView({collection: this.collectionUser});
This is it

Backbone view that render child views of the same type causes endless loop

I have a category model that has child category models (That works fine) via this code:
var ImageSetCategory = Backbone.Model.extend({
childrenCategories : new Array(),
initialize: function () {
var self = this;
if (this.has('childrenCategories')) {
$.each(this.get('childrenCategories'), function () {
var category = new ImageSetCategory(this);
self.childrenCategories.push(category);
});
}
}
});
I also have a view that uses this model and renders all the children categories. (basicly, I'm attempting to make a tree view) It loops through the child categories using jquery, instantiates a new version of its self with each child category as the model, and renders it. But I'm hitting an endless loop that constantly is trying to process the same model.
var ImageSetCategoryView = Backbone.View.extend({
tagName: 'li',
className: 'nested-category',
template: Handlebars.templates.imageSetCategoryView,
render: function() {
var self = this;
var templateHtml = this.template(this.model.toJSON());
self.$el.html(templateHtml);
// *****************************
// ENDLESS LOOP
// this is always the same model from the array
// *****************************
$.each(self.model.childrenCategories, function () {
var categoryView = new ImageSetCategoryView({ model: this });
self.$el.children('ul').append(categoryView.render().el);
});
return this;
},
});
Why is this causing an endless loop? Am I'm not following best practices? My background is C# so I'm trying to accomplish this in an OOP way.
The reason is that all instances of ImageSetCategory share the same childrenCategories array. This way in ImageSetCategory.initialize function you create circular references (ImageSetCategory.childrenCategories points to the array and ImageSetCategory.childrenCategories[0] points to ImageSetCategory itself). This makes $.each in ImageSetCategoryView.render iterate over the same model. To avoid it you should initialize array inside of ImageSetCategory.initialize function:
var ImageSetCategory = Backbone.Model.extend({
initialize: function () {
var self = this;
this.childrenCategories = [];
if (this.has('childrenCategories')) {
$.each(this.get('childrenCategories'), function () {
var category = new ImageSetCategory(this);
self.childrenCategories.push(category);
});
}
}
});
To learn more about why this happens read about prototypes in JavaScript and how they are used to implement object-oriented paradigm.

Can't get a views/collection to show?

I can't seem to get a test backbone.js app working and I have no idea what I am doing wrong.
http://jsbin.com/iwigAtah/1/edit
I modified your code a little bit and here's what I came up with.
// Backbone Objects
var Item = Backbone.Model.extend({});
var List = Backbone.Collection.extend({
model: Item
});
var ListView = Backbone.View.extend({
initialize: function(options){
// collection is now passed in as an argument
// this line isn't necessary but makes it easier to understand what is going on
this.collection = options.collection;
console.log(this.collection.models);
}
});
// Create a new empty collection
var test = new List();
// Create a new item model and add it to the collection
var testItem = new Item();
test.add(testItem);
// Create a view with your new collection
var g = new ListView({
collection: test
});
The main issue you were having is that you weren't actually adding your model to the collection.

Setting Backbone attributes in a model in a nested collection

Pretty new to Backbone JS and I need to know the 'right' way of looping through and setting attributes on models in a collection that is within a model.
My models look like this:
var mediaItem = Backbone.Model.extend({
});
var mediaItems = Backbone.Collection.extend({
model: mediaItem
});
var story = Backbone.Model.extend({
initialize: function () {
this.MediaItems = new mediaItems(this.get('MediaItems'));
this.MediaItems.parent = this;
}
});
What I want to do is loop through the MediaItems in a given story and set the width and height of each. If I do it like this...
storyInstance.MediaItems.each(function (mediaItem) {
mediaItem.set('Width', 200);
mediaItem.set('Height', 100);
});
...then the MediaItem models within the storyInstance.MediaItems property are correctly updated, but the objects within storyInstance.attributes.MediaItems are not. And it's the attributes tree that appears to be used when I subsequently call toJSON() on the Story model.
I can probably amend the above to loop through attributes instead, but I get the feeling I've set up the models wrong or there's a more standard way of doing this?
Thanks.
Probably initialize something other than what you expected.
The below code
var story = Backbone.Model.extend({
initialize: function () {
this.MediaItems = new mediaItems(this.get('MediaItems'));
this.MediaItems.parent = this;
}
});
should have been
var story = Backbone.Model.extend({
initialize: function () {
this.MediaItems = this.get('MediaItems');
this.MediaItems.parent = this;
}
});
and instantiating items should be done with instantiation of story model like
var storyInstance = new story({
MediaItems: new mediaItems()
})
then
story.MediaItems.each(function (mediaItem) {
mediaItem.set('Width', 200);
mediaItem.set('Height', 100);
});
would result updating both
Edit: Did not realize this was from '13. It showed up in questions tagged backbone.js and I did not notice the date/time till now.
Try to check for the instance of Array in the initialize section.
var story = Backbone.Model.extend({
initialize: function () {
if(this.get('MediaItems') instanceof Array){
this.MediaItems = new mediaItems(this.get('MediaItems'));
}
else {
this.MediaItems = this.get('MediaItems');
}
this.MediaItems.parent = this;
}
});

Fetch data having a specific id defined in the view instance

I need to fetch data having a specific id
and which id is defined in the view instance.
Here the example, see the comments in MyModel definition:
// my view instance
var myView = new MyView({
model: {id: 12321}
});
MyView = Backbone.View.extends({
initialize: function()
{
myModel.fetch();
}
});
MyModel = Backbone.Model.extends({
url: function url ()
{
// how to get the id passed to view instance?
return "http:..../id/" + this.id;
}
});
Model should not has any knowledge of the existence of the View, so the View should be the one that sais to the Model which id to fetch:
MyView = Backbone.View.extends({
initialize: function()
{
myModel.id = this.model.id;
myModel.fetch();
}
});
(I've used your example code as template for my example, but I have to say I feel several weird things on it, I suppose is just a matter of taste)
Update: My very personal taste opinions
Is very difficult to do this but as you requested I'll share with you my very personal code review of your example code. Take this as it is: a very humble opinion.
this.model confused
I would not use attribute names that can create confussion:
var myView = new MyView({
model: {id: 12321}
});
Into this instance this.model is making reference to a raw Hash but in a Backbone context this is against the intuitive feeling that this is gonna be a Backbone.Model.
I rather change it for something like this:
var MyView = Backbone.View.extend({
initialize: function( opts ){
this.model_id = opts.model_id;
}
})
var myView = new MyView({ model_id: 12321 });
I think this naming is more intuitive.
close variables scopes
This code can only works if myModel is in an scope bigger that it should be:
MyView = Backbone.View.extends({
initialize: function()
{
myModel.fetch();
}
});
I rather prefer using more encapsulated scopes, even if myModel has been declared in the out-side context of your View the View should use a variable of its private context. For example
var MyView = Backbone.View.extends({
initialize: function( opts ) {
this.model = opts.model;
this.model.fetch();
}
});
var myView = new MyView({ model: myModel });
Check the detail that I have also added var in front of MyView because if not MyView will be a window global variable.
use the Backbone urlRoot
In your example, this ...
MyModel = Backbone.Model.extends({
url: function url ()
{
// how to get the id passed to view instance?
return "http:..../id/" + this.id;
}
});
... can be summarized as this:
MyModel = Backbone.Model.extends({
urlRoot: "http:..../id"
});

Categories

Resources