I'm trying to make a small backbone.js app, but struggle with the order of things.
In my html file, I have two script blocks in the header:
<script type="text/template" id="model-template">
<a href="#"><%= title %></a>
</script>
<script type="text/javascript">
jQuery(function(){
window.model.fetch();
});
</script>
In my app.js, I have defined a simple model, view and a router.
(function($) {
window.MyModel = Backbone.Model.extend({
url: '/mymodel'
});
window.mymodel = new MyModel();
$(document).ready(function() {
window.MyModelView = Backbone.View.extend({
template: _.template($('#mymodel-template').html()),
initialize: function () {
_.bindAll(this, 'render');
},
render: function () {
var renderedContent = this.template(this.model.toJSON());
$(this.el).html(renderedContent);
return this;
}
});
});
window.MyApp = Backbone.Router.extend({
routes: {
'': 'home'
},
initialize: function () {
this.myModelView = new MyModelView({
model: window.mymodel
});
},
home: function() {
var $body = $('body');
$body.empty();
$body.append(this.myModelView.render().el);
}
});
$(function() {
window.App = new MyApp();
Backbone.history.start({pushState: true});
});
})(jQuery);
The application is served by a simple sinatra application. The url /mymodel
serves a static json file:
{
"title": "My Model",
}
When loading the application, I get an error in the javascript console:
Uncaught ReferenceError: title is not defined
The problem seems to be, that the view renders itself before the model is fetched from the server. Why is that?
Yesterday, I followed the first two backbone.js screencasts from PeepCode. I have tried to compare my application with the one that came out of the screencasts, but cant't see a reason for why my application want work.
Any suggestions?
You can also take advantage of the deferred object http://api.jquery.com/category/deferred-object/ that
Backbone.Model.fetch()
returns, like this:You may want to create an extension of the backbone model that stores a deferred object on your model that you can reference, like this:
Then in your view render method, you can just say this:
It can be very handy to use an extended model and follow this pattern throughout your backbone application.
Clearly from the previous answers, you know that you need to render on the fetch success callback, however I think you problem is a bit more than that. Namely, your home route is used to build myModelView immediately rather than when its data loads. This is happening because you are calling render() in order to append to body. Instead, try and initialize the view with an existing element. This way you can delay the call for render until fetch has completed:
Now, you haven't called render() yet, but your view is successfully attached to the DOM as you intended.
You can always set-up a default title using the 'defaults' option: http://documentcloud.github.com/backbone/#Model-defaults.
In this case, you'll want to render the view in the success callback.
In this case you should bootstrap your model data so that it's available on page load.
Instead of
put something like this in (if using a .erb)
Otherwise you need to render the view once the model is fetched e.g.
bind the view to render when the model changes
or handle the success of the model.fetch and render the view