Backbone: Get selection of collection without creating new collection - backbone.js

I have a collection A and a view A
collection A:
model {type: A}
model {type: B}
view A use collection A and all its models.
If I add a new model to collection A, this model is added to view A.
In view B I want to use collection A as well, but not all its models, only models with type B. But I want to use all listeners in View A.
So, If I add a new model with type B in view A, listeners in view B should intercept this and add it to view B.
I can make two different collections, and use two listeners. But this looks dirty.
Is there a way to get get a selection of a collection into a new collection, but keep the same listeners and backbone functions as if it was just a reference to the main collection?

One solution would be to have one collection replicate another (applying a filter at the same time).
From https://jsfiddle.net/t8e6Ldue/
var collectionB = new FilteredCollection(null, {
source: collectionA,
filter: function(model) {
return model.get('type') === 'B';
}
});
see the JSFiddle for full code

Related

Trying to add a collection to a model and render it in multiple places in a view

I'm trying to build an app that allows you to create items in a view in multiple places.
For instance, I can add a model from a collection when I create a new model in the parent collection.
The problem I'm having is, when I add the collection to the model and it iterates, it's adding the collection for each loop. So it ends up with LOTS of collections in the model that are repeated.
The parent model render has the following loop:
this.noteTasksViewAdding = new NoteTaskListViewAdding({ collection: tasks });
$('.note-tasks-list-all').append(this.noteTasksViewAdding.render().el);
this.collection.each(function(note){
var view = new NoteView({ model: note });
$('#items-list').prepend(view.render().el);
});
Then the model has the following render in it:
render: function() {
this.noteTasksViewAdding = new NoteTaskListViewAdding({ collection: tasks });
$('.note-tasks-list-all').append(this.noteTasksViewAdding.render().el);
this.$el.html(this.template(this.model.toJSON()));
return this;
}
What I want to have happen is that the collection is added to the model when it's rendered. I'm open to any suggestions on how to do this better.
Thanks!
I faced the problem as well. The solution is to clear the view before you set the collection. In your case, when you set parent view, you might do this:
$('.note-tasks-list-all').html(this.noteTasksViewAdding.render().el);
Then you can append your collection members.

View event reflected in collection convention

What is the best way to remove a model from a collection that has been removed in the DOM. Let me ask a better question, how do I keep views in sync with a collection?
remove the view first, while removing execute
this.model.collection.remove(this.model);
you can check with conditions to whether current view has a model, and that model has a collection etc before you execute the same.
I've followed the backbone Todos example application. This keeps view state up to date with collection.
Pass models to any view created like so:
var someView = new SomeItemView({ model: modelFromCollection });
Then listen to events on that model and react from the view:
initialize: function() {
this.listenTo(this.model, 'destroy', this.remove);
// listen to other events ...
}

Backbone and Marionette convention for representing an itemview that is an object and a collection

So I have an object that looks something like this
{
first_name: 'Matt',
last_name: 'Damon',
movies: [{name: 'mov_name1', director: 'Sven'}, {name:'mov_name2', director: 'Joe'}]
}
There is an endpoint that will return this, and I will use fetch to get this data and put it in a model or ItemView. (I have to use fetch because I really want a collection of these objects, so I'll call fetch on the collection.) However, the representation of the object should not be a model alone, it should be a model (or ItemView), and the movies attribute should be a collection, since when I display the row for this object it should be a CompositeView with a model and a collection. My question is how do I convert this object representation to a model and collection after a fetch called on the model?
Sorry it's a bit confusing to explain...
do a fetch on your collection and then for each element create a model and a collection that you can pass then to a compositeView
something like this
mycollection = new MyCollection();
mycollection.fetch();
mycollection.each(function(item){
var actorModel = new ActorModel({firstName : item.get('first_name'),
lastname: item.get('last_name')});
var moviesCollection = new MoviesCollection(item.get('movies'));
var xCompositeView = new XCompositeView({model:xmodel,
collection:moviesCollection});
});
this way your Compositeview gets a model and a collection and you can render them properly using an itemView for each movie.
hope this helps.
If its not a problem to use another framework, there is one called backbone-relational. It is designed to handle the relations between models. See the zoo example in Backbone-Relational
In the example there is a Zoo model and models has a Animal Collection which consist of animal models. With a single fetch on Zoo model, you will have the animal collection as Backbone collection instead of array of plain objects.

How to update model in collection?

I have the following Backbone.js collection:
var Tags = Backbone.Collection.extend({
url: "/api/v1/tags/"
}),
How do I update one of the models in the collection so that it posts to /api/v1/tags/id and saves the data for that model.
So if I change name of model with id 2 in the collection
It should PUT to
/api/v1/tags/2 with the following data:
name: new name id: 2
I've also recently wanted to update particular model in the collection. The problem was that if I did use just model.save it didn't update the collection. The goal was to change the model in collection, change it on the server, update collection accordingly and not use the sync method. So for example I have my variable collection and I want to change the model with id = 2. So the first thing, I will create an instance model, like this: var model = collection.get(2)Then I will update the attributes on this particular model:model.set({name: 'new name'})Then I will save it to the server:model.save({}, {url:'/api/v1/tags/'+model.get('id')})Then we have to update collection accordingly to the changes:collection.set({model},{remove: false})set method - it's a 'smart' update of the collection with the list of the models you passed in parameters. remove: false parameter - it's a restriction for a collection to remove existing models in collection. More here.
The first thing you can miss is that in your corresponding Tag model you'll need to set "urlRoot" to match the Collection's "url". Otherwise it doesn't know about the collection at all:
var Tag = Backbone.Model.extend({
urlRoot: "/api/v1/tags"
});
var Tags = Backbone.Collection.Extend({
model: Tag,
url: "/api/v1/tags"
});
This is useful if you want to save the tag separately:
var tag = collection.get(2);
tag.set({key: "something"});
tag.save(); // model.save works because you set "urlRoot"
On the collection, "create()" is also "update()" if id is not null. That's not confusing. :) Therefore, this is pretty much equivalent to the previous sample:
collection.create({id: 2; key: "something"});
This will update the existing tag with id=2 and then trigger a PUT.
This is an ancient question; answering because I was searching for the same answer--you've probably long since solved this problem and moved on. :)
You can pass variables to the save method. It accepts all the options which jQuery's ajax method uses (unless you overrided Backbone.Sync)
You could do something like:
model.save( { name:'new name' } );
The id and PUT method will automatically be added by Backbone for you.

Accessing other collection inside backbone model

I have 2 post collections and a model as follows.
# router file
#posts = new MyApp.Collections.PostsCollection()
#posts.reset options.posts
#followed_posts = new MyApp.Collections.PostsCollection()
#followed_posts.reset options.followed_posts
# Post model file
class MyApp.Models.Post extends Backbone.Model
paramRoot: 'post'
follow_post: ->
# ajax call
console.log "_________Index:#{this.collection.indexOf(this);}"
console.log this.collection
console.log "_________Followed:"
console.log #followed_posts
class MyApp.Collections.PostsCollection extends Backbone.Collection
model: MyApp.Models.Post
url: '/posts_all'
What I am trying to do is when one of the model changed in one collection, I want to update the other model in other collection too.
These collections may or may not hold same models.
So let's say if a model in #posts changed in my Post model, I want to update that model in #followed_posts too. If #followed_posts doesn't have that model, I need to add a duplicate of the model to #followed_posts collection.
I can access the collection that model belongs, but I cannot access the other collection.
Any ideas appreciated, thanks.
If the two collections are antisocial and can't talk directly to each other, which is usually good design, then you'll need an intermediary -- a global event dispatcher. When a model changes, propagate that event to the dispatcher along with a reference to the model. Listen for the event in the other collection and use the model passed to check for existence and respond as needed.
EDIT:
Backbone's documentation mentions this pattern:
For example, to make a handy event dispatcher that can coordinate
events among different areas of your application: var dispatcher =
_.clone(Backbone.Events)
But in fact, this is such a common pattern that the Backbone object itself is extended with Events. So you can just do:
// In your Post model
#on "change", -> Backbone.trigger "post:change", this, #collection
// And then something like this in the collection class definition:
#listenTo Backbone, "post:change", (model, collection) =>
if post = #get model.cid
post.set model.toJSON()
else
#add model
Also, is followed posts a subset of posts? If so, why not put an attribute on the model designating it as followed? Then you could find all followed posts with a simple filter function.
I would strongly suggest that you should consider having a single collection and add some kind of attribute in the model to differentiate between what kind of posts they are.

Resources