Frustratingly, most ‘tutorial’ examples of backbone.js apps assume a clean model slate. I-.e. that the model collections are empty initially, until a user adds an item. Of course this is not the case in a real world app, where you 开发者_StackOverflow中文版usually have an existing collection to start with from the back end store.
I would like to know how people deal with existing collections in backbone. Specifically:
How do you render a collection after it has been
fetch
ed? Is is just a case of iterating through the collection? Should this be trigger by some event?The backbone docs talk about ‘bootstrapping’, which I understand means using data that is available on the initial load (this also makes sense from an SEO point of view). But how does this work in practice? The data is dumped into JS on the server side? Or the JS examines the DOM?
I feel like this is a poor question, but I expect to expand it based on the answers.
EDIT
So it seems that the consensus is to add the data as party of the JS and process that on page load.
One big disadvantage I see with this technique is that the information is not available for search engine spiders. From that perspective it might be better to extract it from the DOM (although I haven't seen anyone do it that way). Or maybe add the HTML server side and stick the data in the JS?
I came across the same situation as you, I don't always want my data bootstrapped initially (especially if its from a third-party api call). I haven't come across any tutorials that do this but looking through the documentation its actually pretty easy. You just need to bind the 'reset' event (this is fired when the entire collection is repopulated) on your collection and render. Heres a quick example:
my_application.js
window.MyApplication = {
Models: {},
Collections: {},
Views: {},
Routers: {},
init: function() {
// Start the data loading
this.someItems = new MyApplication.Collections.Items();
this.someItems.fetch();
// Start rendering the UI before the data is ready
new MyApplication.Routers.Items(this.someItems);
Backbone.history.start();
}
};
routers/items_router.js
MyApplication.Routers.Items = Backbone.Router.extend({
routes: {
"" : "index"
},
initialize: function(collection) {
this.collection = collection;
},
index: function() {
var view = new MyApplication.Views.ItemsIndex({ collection: this.collection });
$('.items').html(view.render().el);
}
});
views/items/items_index.js
MyApplication.Views.ItemsIndex = Backbone.View.extend({
initialize: function() {
_.bindAll(this, "render");
// Once the collection is fetched re-render the view
this.collection.bind("reset", this.render);
},
render: function() {
console.log(this.collection.length);
// Render content
return this;
}
});
As far as rendering collections, yes I normally iterate over a collection and create a child view for each of the models. Here is a link that might be helpful on that http://liquidmedia.ca/blog/2011/02/backbone-js-part-3/
When should you render it? Well that's a tough one to answer but I wouldn't say it's in response to any particular event. One thing that I like is that we have one main view that renders sub views which render other sub views. As a convention we don't render directly to the DOM but once all the sub views are rendered, we append the main view to the DOM and the whole page shows up immediately. This avoids the 'flash of unstyled content'
Regarding bootstrapping I see from the contents that you read the FAQ, and that's just what I've done in practice. I use ASP.Net MVC 3 so my server side rendered view would have something like (though I wouldn't put 'books' on the global namespace normally):
<script type="text/javascript">
books = new BooksCollection();
books.reset(@Html.ToJson(Model));
</script>
Hope that's helpful.
Actually, I have done some work on Backbone for a little while, and I've found that Bootstrapping data is really helpful in some cases, when you know that you would require that data AS SOON as the page loads (thus reducing an extra AJAX call)
In Symfony, I do it by rendering the required data in this way:
<script type="text/template" id="__user-boostrap">
{% echo your data from php or render a controller in symfony or whatever server side script/framework you want %}
// for example in symfony2, I do:
{% render "myBundle:Core:getUser" %}
</script>
Now, in the initialize() function, you can lift this data directly from DOM, and start doing the work as usual:
For example, in my Router, i do
myApp.Router = Backbone.Router.extend({
var data = JSON.parse($('__user-bootstrap').html());
var __games = new myApp.Games();
__games.reset(__games.parse(data.games));
var gameList = new myApp.GameListView({ collection: __games });
$(this.gameView).html(gameList.$el);
});
Hope this helps...
精彩评论