My ultimate goal is to append the JSON data to ul#tweets, each as individual hidden list items. They will then, one by one over time, become visible/shown on the screen, and then be removed from the ul#tweets list.
Once the number of hidden items drops below a certain amount, I want to re-append the JSON data. When this happens, I am not worried about duplicate items.
I tried to setup a test by creating a function with a timeout so that every 5 seconds it would append the JSON data to the list.
However, though my app loads the initial data on pageload fine, when I create a function to be run within $(document).ready({}) – it won’t work.
I do know, however, that I can append the JSON data manually in the console after page load (same code as below without wrapping it in the function or the doc.ready).
Thanks for the help!
Function:
$(document).ready(function(){
updateTweets = function() {
newTweets = new Tweets();
newTweets.fetch();
newTweets.each( function(tweet) {
console.log('test'); // this doesn't work
view = new TweetView({ model:tweet });
$('#tweets').append(view.render().el);
});
setTimeout(updateTweets, 5000);
};
updateTweets();
});
Here is my Code
// MODEL
window.Tweet = Backbone.Model.extend({});
// COLLECTION
window.Tweets = Backbone.Collection.extend({ model: Tweet, url: '/tweets' });
// SET GLOBAL VARIABLE FOR NEW TWEETS COLLECTION
window.tweetList = new Tweets();
$(document).ready(function() {
// MODEL VIEW
window.TweetView = Backbone.View.extend({
tagName: 'li',
className: 'tweet',
initialize: function() {
_.bindAll(this, 'render');
this.model.bind('change', this.render);
this.template = _.template($('#tweet-template').html());
},
render: function(){
var renderedTweets = this.template(this.model.toJSON());
$(this.el).html(renderedTweets);
return this;
}
});
// COLLECTION VIEW
window.TweetListView = Backbone.View.extend({
template: _.template($('#tweet-list-template').html()),
initialize: function() {
_.bindAll(this, 'render');
this.collection.bind('reset', this.render);
},
render: function() {
var $tweets,
collection = this.collection;
$(this.el).html(this.template({}));
$tweets = this.$('#tweets');
collection.each(function(tweet){
var view = new TweetView({
model: tweet,
collection: collection
});
$tweets.append(view.render().el);
});
return this;
}
});
// ROUTER
window.TweetListDisplay = Backbone.Router.extend({
routes: {
'': 'home'
},
initialize: function(){
this.tweetListView = new TweetListView({
collection: window.tweetList
});
},
home: function() {
var $container = $('#container');
$container.empty();
$container.append(this.tweetListView.render().el);
},
});
// DECLARE AND START APP
window.app = new TweetListDisplay();
Backbone.history.start();
}); // close $(document).ready({});
You call fetch here
And then right after start processing the collection as if it has been populated, here
fetchis an ASYNCHRONOUS operation, which means that after you fire it, the rest of the program will continue to execute immediately after, regardless if the ajax-call launched by thefetchhas returned or not. So when you start processing the collection, your fetch hasn’t yet returned and the collection is still empty.There are 2 ways you can correct this situation. Let’s start by making a function
processCollectionthat does to the collection exactly what you want:1 The callback function (I don’t like these)
Now
processCollectionwill be called right after the fetch has succeeded.2 Bind to events (I prefer this)
When the fetch returns successfully, it will populate the collection and fire a
reset-event. This is a good place to tie your processing event, because you know that now the collection is populated. Also I find that there is slightly less scoping problems with events than with callbacks.Hope this helps!