Fire a remove event on fetching a collection - backbone.js

This is an odd behavior I think. I have two "section" instances. Each one with an exercises collection. Then, I do a fetch for each collection and here is the problem. From server can I to receive some model that can be in the two collections at the same time. But this wouldn't be a problem because they are independent instances.
Model:
class App.Models.Section extends Backbone.RelationalModel
relations: [
{
type: Backbone.HasMany
key: 'exercises'
relatedModel: 'App.Models.Exercise'
collectionType: 'App.Collections.Exercises'
reverseRelation:
key: 'section'
includeInJSON: false
}
]
View:
class App.Views.Section extends Backbone.Views
initialize: ->
#collection.bind 'add', #renderExercise
#collection.bind 'remove', #unrenderExercise
#subviews = {}
renderExercise: (exercise) =>
view = new Baskeitor.Views.ExerciseShow model: exercise
#subviews{exercise.cid} = view
#$el.append view.render().el
unrenderExercise: (exercise) =>
#subviews{exercise.cid}.remove()
delete #subviews{exercise.cid}
Two instances:
section1 = new App.Models.Section
section2 = new App.Models.Section
Fetch in the two exercises collection:
section1.get('exercises').fetch({ data: params, remove:false })
section2.get('exercises').fetch({ data: params, remove:false })
I lied, this is my problem with Backbone. In a first time the collections receive their models and I generated a view for each model (an event 'add', so I render the exercise view). But next, for some reason than I don't understand, Backbone trigger a remove event and removes all models repeated. In resume, only I can have in the collections whose models aren't in the other.
EDIT
I have identified the problem. The matter is that ids are duplicates. If I change their ids manually, then all works fine. But otherwise it doesn't do it. But I think this don't have sense because I am instanciating two differents sections. Each section would have its own array with the ids of exercises.

Finally I have just remove Backbone-Relational from my project.

Related

Right way to initialize backbone collection

Having a model, it presumaly would be nice to use it in a collection. However I am a bit puzzled with the collections and colleciton initialization.
May be I am missing the idea of the collection itself. So probably the first question would be can we have a collection and then a have a instances of the collection?
Secondly, how do we create an instance of the collection?
So here is a snippet of my code:
Model:
CarInsuranceApp.Models.Row = Backbone.Model.extend({
defaults: {
id: null,
....
higher_excess: null,
}
});
Collection
CarInsuranceApp.Collections.Table = Backbone.Collection.extend({
model: CarInsuranceApp.Models.Row,
// my collection methods
filter: function() {
...
Initialize collection
CarInsuranceApp.results = new CarInsuranceApp.Collections.Table( myArraOfObjects );
This gives back an output of:
child {models: Array[19], length: 19, _byId: Object, _idAttr: "id", _events: Object…}
So the question would be what is this thing child? Also an instance of the backbone.collection doesn't respond to methods, such as where, is there any way to call super methods?

using Backgrid and Backbone-relational

I have a model which has HasMany items in it.
var Checklist = Backbone.RelationalModel.extend( {
url: {{ url }}
relations: [ {
type: Backbone.HasMany,
key: 'items',
relatedModel: ChecklistItem,
collectionType: ChecklistItemCollection,
}],
});
I instantiate the model var checklist = new Checklist();
now I initialize Grid and fetch the checklist.
var grid = new Backbone.Grid({columns:columns, collection: checklist.get('items'));
checklist.fetch({reset:true});
I can see in Checklist's parse method that it has retrieved data from the server.
But the grid view doesn't show any data for it.
(When I used plain Backbone.model instead of backbone.RelationalModel, everything worked fine. So I know my setup is correct other than the backbone-relational + backgrid interaction is missing)
I'm new to backbone/javascript/backgrid/... world
I guess I need to hook up some events to make it work.
Please share an insight!

How to store a reference to a Collection in a Model in Backbone.js?

When creating new collection (Choices) I want to set a property on it (ex: _question) which links back to the containing Model (MultipleChoiceQuestion)
This took me quite a bit of time to figure out, so in case somebody in the future has this problems...here's the code I ended up writing.
I discovered, unlike Model, Collection's initialize() function accepts 2 parameters. The first is models (which is a list of models you can initialize the collection with). The second is options (what you want). For a while my Collection started out with 1 model inside and I couldn't figure out why. Turns out I was passing my options into the models field.
THE CONTAINING MODEL:
m.MultipleChoiceQuestion = Backbone.Model.extend({
initialize: function(){
//NULL as first parameter because we don't want models
this.choices = new c.Choices(null, {
_question: this //this is referring to current question
}); //choices Collection is this
}
});
THE COLLECTION
c.Choices = Backbone.Collection.extend({
initialize: function(models, options){
this._question = options._question;
},
model: m.Choice
});
I actually found that although my 1st answer technically works, there's a plugin that makes care of storing collections in models (and creating appropriate One->Many, One->One and Many->One relationships
https://github.com/PaulUithol/Backbone-relational
Using that plugin you store the parent question as an ATTRIBUTE
m.MultipleChoiceQuestion = Backbone.RelationalModel.extend({
relations: [{
type: Backbone.HasMany,
key: 'choices', //says to store the collection in the choices attribute
relatedModel: m.Choice, //knows we are talking about the choices models
includeInJSON: true, //when we do toJSON() on the Question we want to show serialize the choices fully
reverseRelation: {
key: 'question', //in the CHOICE object there will be an attribute called question which contains a reference to the question
includeInJSON: false //when we do .toJSON on a CHOICE we don't want to show the question object (or maybe we want to show the ID property in which case we set it to "id")
}
}],
coolFunction: function () {
this.get('choices').each(function(choice){
choice.doSomethingChoicey();
});
}
});
So now if we are in the choices model we can fully reference anything in the parent question:
m.Choice = m.RelationalModel.extend({
coolFunction: function(){
this.get('question').doSomemethingQuestiony();
var question_numer = this.get('question').get('question_number');
}
});

Using Composite Views with Backbone Marionette and Relational

I've been using Marionette for a couple of weeks and just discovered Backbone Relational so I'm trying to figure out how to integrate the two. Ideally, I would like to use a composite view to render data that is structured like this where each 'item' has its own item view:
list : {
name : 'List 1',
items : [
item1 : {
name : 'Item 1',
id : 1
},
item2 : { ... }
item3 : { ... }
]
}
Normally with composite views you need to have a collection of models that it will iterate through to render each item. With relational, I've just got one model (the list) and that model has a collection (items) within it. Is it possible to render this out using Marionette's views or do I need to use a plain Backbone view and handle the rendering and iteration myself?
This is quite common, and easy to do. In your CompositeView definition, you can specify the collection to use in the initialize method.
Backbone.Marionette.CompositeView.extend({
// ...
initialize: function(){
this.collection = this.model.get("childcollection");
}
});

backbone.js: define an initial set of models when creating a collection

I'm creating a backbone view for displaying a list of folders created by user in my webapp. but I want to have a default entry like no folder to be displayed in the list as well.
Instead of inserting the DOM inside the view, I want to just add a model to the collection which does not get synced to server but is just used to be rendered in the view.
Is there a way I can do this? I tried this an failed...
var def = {'name': 'none', 'selected': 'true'};
var coll = new app([def]);
// model here
var appitem = Backbone.Model.extend({
defaults: {
name: '',
id: '',
selected: 'false'
}
});
// collection here
app = Backbone.Collection.extend({
model: appitem,
url: '/apps'
});
You should not alter your models based on what the view needs.
If you need to display a 'no folder' entry, than it belongs in the view.
Don't complicate your life by adding data without meaning to the model layer. Keep it in the view.

Resources