My model urlRoot:
urlRoot: function() {
if (this.id != null ) {
return 'notes/' + this.id;
} else return 'notes';
}
Function:
window.show_note = function (note_id) {
var note = new Memo.Models.Note([], { id: note_id });
note.fetch({
success: function (collection, note, response) {
var noteObj = collection.get("0");
var noteView = new Memo.Views.FullNote( {model: noteObj }, {flag: 0 } );
$('.content').html(noteView.render().el);
}
});}
{ id: note_id } - I post this to server to get note by id
I want to do 'set' or 'get' functions on model 'note' after note.fetch in a callback function - success, but only I have is error: 'Uncaught TypeError: note.set is not a function'.
If I do this way: 'var noteObj = collection.get("0");'
I get that I need but I still can`t use get or set.
You should set urlRoot to:
urlRoot: '/notes'
And backbone will figure out that it needs to add the id to the url. (docs)
Assuming Memo.Models.Note is a model and not a collection, the above snippet should be like this:
window.show_note = function(note_id) {
var note = new Memo.Models.Note({ id: note_id });
note.fetch({
success: function (model, response, options) {
var noteView = new Memo.Views.FullNote({
model: model
}, {flag: 0 });
$('.content').html(noteView.render().el);
}
});
};
Note the argument passed to new Memo.Models.Note. A backbone model constructor takes two arguments: attributes and options (docs) as opposed to a collection, which takes models and options (docs). So you'll want to add the hash with the id property as the first argument.
Also note the function signature of the success callback. For a model the success callback takes three arguments: model, response and options (docs). You'll be interested in the model argument because that is the fetched backbone model. response is the raw response data.
I hope my assumptions are right and this is the answer you are looking for.
Related
I need to be able to pass the server some info when calling fetch on a Backbone collection. On my front-end I have this code, passing data:{} to the fetch function along with the success and error callbacks. Looking at the docs for Backbone fetch:
http://backbonejs.org/#Collection-fetch
perhaps I am not passing in the parameters correctly to the fetch function? Perhaps they should be in an array []...
var lineupCollection = new LineupCollection([]);
var loadTeamsOnPageLoad = (function() {
lineupCollection.url = '/api/lineups';
lineupCollection.fetch(
{
processData: true,
data: {
team_id:$("#team_id").attr("value")
}
},
{
success: function (result) {
if(window.teamDashboardTableView === undefined){
window.teamDashboardTableView = new TeamDashboardTableView({el: $("#team-dashboard-table-div")});
}
window.teamDashboardTableView.render();
},
error: function (err) {
setTimeout(function () {
alert('error fetching lineupCollection - ' + err.message);
}, 1);
}
}
);
})();
which will load a Backbone collection into a table.
It's call this method on the back-end:
exports.getBackboneLineups = function(req,res,next){
var user_id = req.mainUser._id;
console.log('req.params',req.params); //empty {}
console.log('req.team',req.team); //undefined
console.log('team_id',req.team_id); //undefined
console.log('req.data',req.data); //undefined
console.log('req.body',req.body); //empty {}
var team_id = req.team._id; //undefined EXCEPTION, can't read property _id of undefined
var system_db = req.system_db;
var Lineup = LineupModel.getNewLineup(system_db,user_id);
Lineup.find({team_id:team_id}, function (err, lineups) {
if (err) {
return next(err);
}
res.json(lineups);
});
};
however, I am totally failing as far as how to access the data that I supposedly past to the server from the client. I can't really find a good example and I am getting tired of guessing. What's the best way to do this?
edit:
also tried passing {data:{}, success: function(), error: function()} all in the same JavaScript object, but that didn't work.
fetch only takes one argument (see http://backbonejs.org/#Collection-fetch). Instead, you should probably alter your backend to specify the team id in the resource's URL. For example:
lineupCollection.url = function(){ return '/api/lineups?team_id=' + this.team_id; };
lineupCollection.team_id = $("#team_id").attr("value");
lineupCollection.fetch({ success: ..., error: ...});
// file one
// how to call the choicesCollection setnextOne in ChoicesModel default function(object)
var ChoicesModel = Backbone.Model.extend({
defaults: function() {
// this.collection ??
return {
seq_id: choicesCollection.setnextOne(),
subject: ""
};
},
initialize: function() {
console.log(this);
if (!this.get("seq_id")) {
this.set({"seq_id": this.defaults().seq_id});
}
}
});
// file two
var ChoicesCollection = Backbone.Collection.extend({
model:ChoicesModel,
setnextOne: function() {
if (!this.length) return 0;
return +this.last().get('seq_id') + 1;
},
// sort
comparator: function(choice) {
return choice.get('seq_id');
}
});
// file three
var choicesCollection = new ChoicesCollection();
Giving some more insight into Manikandan's answer...
If you look at the backbone code you'll see the following (I've removed some bits):
var View = Backbone.View = function(options) {
options || (options = {});
_.extend(this, _.pick(options, viewOptions));
};
// List of view options to be merged as properties.
var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
As you can see_.pick is used to white list a sub-set of properties from the options passed in. The View prototype is then extended to bolt on these properties (if they've been passed).
In short, the following properties are automatically thrown onto your view if you pass them as options:
model, collection, el, id, attributes, className
As per the backbone documentation you should access the collection by this.collection once you added model to collection. Or you need to send collection option when you create a model.
I need to pass a value from the view to each models inside a collection, while initializing.
Till Collection we can pass with 'options' in the Backbone.Collection constructor.
After this, is there any technique where I can pass the some 'options' into each models inside the collection?
var Song = Backbone.Model.extend({
defaults: {
name: "Not specified",
artist: "Not specified"
},
initialize: function (attributes, options) {
//Need the some_imp_value accessible here
},
});
var Album = Backbone.Collection.extend({
model: Song
initialize: function (models, options) {
this.some_imp_value = option.some_imp_value;
}
});
You can override the "_prepareModel" method.
var Album = Backbone.Collection.extend({
model: Song
initialize: function (models, options) {
this.some_imp_value = option.some_imp_value;
},
_prepareModel: function (model, options) {
if (!(model instanceof Song)) {
model.some_imp_value = this.some_imp_value;
}
return Backbone.Collection.prototype._prepareModel.call(this, model, options);
}
});
Now you can look at the attributes passed to the model in 'initialize' and you'll get some_imp_value, which you can then set on the model as appropriate..
While it appears to be undocumented, I have found that in at least the latest version of backbone (v1.3.3) that the options object passed to a collection gets passed to each child model, extended into the other option items generated by the collection. I haven't spent the time to confirm if this is the case with older releases.
Example:
var Song = Backbone.Model.extend({
defaults: {
name: "Not specified",
artist: "Not specified"
},
initialize: function (attributes, options) {
//passed through options
this.some_imp_value = options.some_imp_value
//accessing parent collection assigned attributes
this.some_other_value = this.collection.some_other_value
},
});
var Album = Backbone.Collection.extend({
model: Song
initialize: function (models, options) {
this.some_other_value = "some other value!";
}
});
var myAlbum = new Album([array,of,models],{some_imp_value:"THIS IS THE VALUE"});
Note: I am unsure if the options object is passed to subsequent Collection.add events
I have 2 models and one collection. JobSummary is a model, JobSummaryList is a collection of JobSummary items, and then I have a JobSummarySnapshot model that contains a JobSummaryList:
JobSummary = Backbone.Model.extend({});
JobSummaryList = Backbone.Collection.extend({
model: JobSummary
});
JobSummarySnapshot = Backbone.Model.extend({
url: '/JobSummaryList',
defaults: {
pageNumber: 1,
summaryList: new JobSummaryList()
}
});
When I call fetch on the JobSummarySnapshot object, it gets everything... Except when I move through the summaryList collection they are all of type object and not JobSummary.
I suppose this makes sense since other than the defaults object, it doesn't know that the summaryList should be of type JobSummaryList. I can go through each item and convert it to a JobSummary object, but I was hoping there was a way to do it without having to do it manually.
Here's my test code (working jsfiddle here):
var returnData = {
pageNumber: 3,
summaryList: [
{
id: 5,
name: 'name1'},
{
id: 6,
name: 'name2'}
]
};
var fakeserver = sinon.fakeServer.create();
fakeserver.respondWith('GET', '/JobSummaryList', [200,
{
'Content-Type': 'application/json'},
JSON.stringify(returnData)]);
var callback = sinon.spy();
var summarySnapshot = new JobSummarySnapshot();
summarySnapshot.bind('change', callback);
summarySnapshot.fetch();
fakeserver.respond();
var theReturnedList = callback.getCall(0).args[0].attributes.summaryList;
_.each(theReturnedList, function(item) {
console.log('Original Item: ');
console.log(item instanceof JobSummary); // IS FALSE
var convertedItem = new JobSummary(item);
console.log('converted item: ');
console.log(convertedItem instanceof JobSummary); // IS TRUE
});
UPDATE:
It occurred to me that I could override the parse function and set it that way... I have this now:
JobSummarySnapshot = Backbone.Model.extend({
url: '/JobSummaryList',
defaults: {
pageNumber: 1,
summaryList: new JobSummaryList()
},
parse: function(response) {
this.set({pageNumber: response.pageNumber});
var summaryList = new JobSummaryList();
summaryList.add(response.summaryList);
this.set({summaryList: summaryList});
}
});
This works so far. Leaving the question open in case someone has comment on it....
Your parse() function shouldn't set() anything, its a better practice to just return the attributes, Backbone will take care of setting it. e.g.
parse: function(response) {
response.summaryList = new JobSummaryList(response.summaryList);
return response;
}
Whatever you return from parse() is passed to set().
Not returning anything (which is like returning undefined) is the same as calling set(undefined), which could cause it not to pass validation, or some other unexpected results if your custom validate()/set() methods expects to get an object. If your validation or set() method fails because of that, the options.success callback passed to Backbone.Model#fetch() won't be called.
Also, to make this more generic, so that set()ing to a plain object from other places (and not only from the server response) also effects it, you might want to override set() instead:
set: function(attributes, options) {
if (attributes.summaryList !== undefined && !(attributes.summaryList instanceof JobSummaryList)) {
attributes.summaryList = new JobSummaryList(attributes.summaryList);
}
return Backbone.Model.prototype.set.call(this, attributes, options);
}
You might also find Backbone-relational interesting - it makes it much easier to deal with collections/models nested inside models.
edit I forgot to return from the set() method, the code is now updated
For a id on a model in backbone, its just id and all lower cased. What if my Id on the server is called UserId. In the parse method for backbone, how do I change UserId to id and use the same names for all other properties?
For eg.
window.User = Backbone.Model.extend({
defaults:
{
UserId: 0, // <--can i just tell backbone that this is my id?
Name: '',
Age: 0
}
parse: function(response){
var model = response;
model.id = response.UserId;
return model;
}
});
Is there a better way to do this?
How about telling backbone model that my id is of type UserId.
You have to say Backbone what property is your id using the idAttribute in the model:
window.User = Backbone.Model.extend({
idAttribute: "UserId",
...
})
and everything works fine :). Backbone will create a id property for you and collections of this model will get() by your UserId.
Do it like so:
parse: function(response) {
var attrs = {};
attrs.id = response.UserId;
return attrs;
}
Parse has the responsibility to return an attributes hash, not a model. As such, you need only transform the response into an attributes hash versus a model as you are doing.
To set the id i would do as mauromartini says. To change any other property you don't need to create any private variables, response from the server is just an object so manipulate it and return it.
window.User = Backbone.Model.extend({
defaults: { UserId: 0 },
parse: function(response){
response.id = response.UserId;
return response;
}
});
you could also add the following before you return the object if you want to keep the model clean:
delete response.UserId;