I'm using Backbone for a personal project in which I created a model named MyModel
. On initialization of this model, I want to populate its attributes from a JSON response from a third-party API:
app.MyModel = Backbone.Model.extend({
url: 'https://api.xxxxxx.com/v12_1/item?id=53444d0d7ba4ca15456f5690&appId=xxxx&appKey=yyyy',
defaults: {
name: 'Default Name'
}
});
This model is used in a collection that will be used in an attribute embedded in a another model:
app.MyModels = Backbone.Collection.extend({
model: app.MyModel
});
app.MyModel2 = Backbone.Model.extend({
// Default attributes
defaults: {
name: 'Default Name'
},
initialize: function() {
this.myModels = new app.MyModels();
this.myModels.on('change', this.save);
}
});
In a view created for MyModel2
, I added a listener to a global element so we can initialize and add instances of MyModel
to MyModels
inside MyModel2
.
app.MyModel2View = Backbone.View.extend({
initialize: function() {
// ...some code...
var self = this;
this.$(".add-myModel").click(function() {
var myModel = new app.MyModel();
myModel.fetch();
self.model.myModels.add(myModel);
});
// ...some code...
},
// ...some code...
});
This is actually doing the intended goal, but throws an error in the console when the element is clicked and the instance added:
backbone.js:646 Uncaught TypeError: this.isNew is not a function
Is this a correct approach in Backbone to populate a model instance from an external API? I'm trying to figure out the reason for this error.
While Stephen is right, he only focuses on the most probable bug and leaves you dealing with everything else. I'll try to expand on this in my answer.
Model URL with ID in a query string
The API's URL is quite complex and it's cumbersome to copy-paste it every time you need it. It's best to get the URL handling in one place and one way to achieve this is with a simple service.
Fill it with the API information.
Then, you can create a base model and collection (or replace the default Backbone behavior).
Then using it is as simple as this:
The below test outputs:
How to populate models with an external API?
If the API you're using adheres to REST principles, there's probably an endpoint which returns an array of objects. This is where the collection should fetch its data.
And it should receive something like:
If you want to add an existing model (referenced with an ID) to a collection:
The response should be a single object:
If you want to create a new model:
Avoid
.on
/.bind
in favor of.listenTo
Passing the context on an event binding is important with Backbone as most parts are classes versus jQuery callbacks which are usually anonymous functions working on local variables. In addition to this, you should use Backbone's
listenTo
instead ofon
.Backbone js
.listenTo
vs.on
Avoid manually binding events with jQuery
In the views, you should use the
events
property to automatically delegates the DOM events to the view's callbacks. It's still jQuery in the background, but cleaner, already integrated into Backbone and the context is automatically passed, so there's no need to use thevar self = this
trick.Creating a new model and fetching it makes no sense from the Backbone design unless you pass an id to the model. Just calling
add
on the collection with an empty object will create a default model.