using Backgrid and Backbone-relational - backbone.js

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!

Related

Loading Model from another model file in extjs

formGrid=me.abstractComponent.query('grid[itemId=grid]')[0],
Objmodel= Ext.create('Ext.document.model.GridModel');
formStore = Ext.create('Ext.data.Store',{
model:Objmodel,
data: data
});
formGrid.bindStore(formStore);
formStore.load();
I've been trying to load the store using the model, but error occurs saying that model not found. Is there any way such that i can load the model from another file in store above?
Store model attribute means you have to give the definition of Model not instance of model
Ext.define('app.model.User', {
extend: 'Ext.data.Model',
fields: ['first', 'last']
});
var store = Ext.create('Ext.data.Store',{
model: 'app.model.User'
});
Now if you want to add data to grid using model
var model = Ext.ModelManager.create({
first: 'Ed',
last: 'Spencer'
}, 'app.model.User');
store.add(model)

Fire a remove event on fetching a collection

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.

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');
}
});

Backbone-relational fetchRelated not sending request

I'm using backbone.js and backbone relational 0.5.0 with a Rails 3.2 backend. I have a Card model which has_many Notes.
Here are my JS models and collections:
Workflow.Collections.Cards = Backbone.Collection.extend({
model: Workflow.Models.Card,
url: '/cards'
});
Workflow.Models.Card = Backbone.RelationalModel.extend({
modelName : 'card',
urlRoot : '/cards',
relations: [
{
type: Backbone.HasMany,
key: 'notes',
relatedModel: 'Workflow.Models.Note',
collectionType: 'Workflow.Collections.Notes',
includeInJSON: false,
reverseRelation: {
key: 'card',
includeInJSON: 'id'
}
}]
});
Workflow.Collections.Notes = Backbone.Collection.extend({
model: Workflow.Models.Note,
url: '/cards/74/notes' // intentionally hard-coded for now
});
Workflow.Models.Note = Backbone.RelationalModel.extend({
modelName : 'note',
urlRoot : '/notes'
});
Normal fetching works great, but when I try fetchRelated in the console, I get an empty array:
card = new Workflow.Models.Card({id: 74}) // cool
card.fetch() // hits the sever with GET "/cards/74" - works great
card.fetchRelated('notes') // [] - didn't even try to hit the server
What's weird is that this works:
card.get('notes').fetch() // cool - GET "/cards/74/notes"
I could use that method and parse the response text, but it feels really dirty.
Anyone know what I'm missing here?
Thanks in advance, this one is really torturing me!
Stu
You should create Card with Note ids array: card = new Workflow.Models.Card({id: 74, notes: [74, 75]}); and change the url method of Notes accordingly:
Workflow.Collections.Notes = Backbone.Collection.extend({
model: Workflow.Models.Note
});
Workflow.Models.Note = Backbone.RelationalModel.extend({
modelName : 'note',
urlRoot : function () {
return this.get('card').url() + '/notes';
}
});
card = new Workflow.Models.Card({id: 74, notes: [74, 75]});
card.fetchRelated('notes');
http://jsfiddle.net/theotheo/5DAzx/
I should have posted my solution a while back - there might well be a better way, but this is the convention I've gone with:
All of the following code is in the card view (which is where the notes are displayed).
First, I bind a renderNotes method to the 'reset' event on the card's notes collection:
initialize: function () {
_.bindAll(this);
this.model.get('notes').on('reset', this.renderNotes);
var self = this;
this.model.get('notes').on('add', function(addedNote, relatedCollection) {
self.renderNote(addedNote);
});
}
I also bind to the 'add' on that collection to call a singular renderNote.
The renderNotes and renderNote methods work like this:
renderNotes: function () {
if (this.model.get('notes')) {
this.model.get('notes').each(this.renderNote);
}
},
renderNote: function (note) {
var noteView = new Workflow.Views.Note({ model: note });
this.$('.notes').append(noteView.render().el);
},
Then, the last piece of the puzzle is to actually hit the server up for the card's notes (which will in turn fire the 'reset' event I bound to above). I do this in the card view's render method:
render: function () {
// render all of the eager-loaded things
this.model.get('notes').fetch();
return this;
},
As #user1248256 kindly helped me work out in the comments on my OP, the confusion was mainly in that I expected fetchRelated to pull down lazy-loaded records - that's actually not the case.
As a side-note, this view is actually a modal and be opened and closed (removed from the page). To prevent the zombie events problem described in this excellent post, I also manually unbind the events mentioned above.

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