Reputation: 1670
I am attempting to update a filtered video
collection when a user
model makes a request to the server. The problem is in the update
method. fetch()
does not get the latest data for the video
collection.
What do I need to fix in update
to get the latest data so the view re-renders properly?
var VideosView = Backbone.View.extend({
tagName: 'ul',
id: 'video-list',
initialize: function() {
var user = this.model;
var _videos = user.get('videos');
user_vids = videos.filter_videos(_videos);
this.listenTo(user, 'request', this.update);
},
render: function() {
user_vids.each( this.addOne, this );
return this;
},
addOne: function(video) {
var videoView = new VideoView({ model: video });
this.$el.append( videoView.render().el );
},
update: function() {
$('#video-list').empty();
_videos = this.model.get('videos');
videos.fetch();
user_vids = videos.filter_videos(_videos)
user_vids.each( this.addOne, this );
}
});
// Instantiate
var videosView = new VideosView({
model: user,
collection: videos
});
$('#allVideos').append( videosView.render().el );
EDIT
Adding additional code:
Here is where videosView
is initialized.
var IndexView = Backbone.View.extend({
initialize: function() {
user = this.model;
},
render: function() {
var videosView = new VideosView({
model: user,
collection: videos
});
$('#allVideos').append( videosView.render().el );
var addVideoView = new AddVideoView({
model: user,
collection: videos
});
$('#addVideo').append( addVideoView.render().el );
}
});
The listenTo
in VideoViews
is listening for what is happening in add_to_user_array
in
the AddVideoView
here:
var AddVideoView = Backbone.View.extend({
tagName: 'div',
template: _.template( AddVideoTemplate ),
events: {
'click #videoSubmitButton': 'submit'
},
initialize: function() {
user = this.model;
},
render: function() {
var template = this.template();
this.$el.html(template);
return this;
},
submit: function(event) {
event.preventDefault();
console.log('form submitted');
var vimeo_id = parseInt( $('#vimeo_id').val() );
var newVideo = {vimeo_id: vimeo_id};
this.collection.create(newVideo, {wait: true});
this.add_to_user_array(vimeo_id);
},
add_to_user_array: function(vimeo_id) {
var _videos = user.get('videos');
_videos.push(vimeo_id);
user.save({videos: _videos}, {wait: true});
}
});
Inside the router I'm instantiating the model and collection:
index: function() {
users = new Users;
users.fetch({
success: function(user_data) {
var user = user_data.findWhere({username: App.username})
videos = new Videos;
videos.fetch({
success: function(video_data) {
var indexView = new IndexView({
model: user,
collection: videos
});
var indexController = new IndexController;
indexController.showView( indexView );
}
});
}
})
}
Upvotes: 2
Views: 1402
Reputation: 55740
First fetch
is Asynchronous
So you are trying to filter the collection immediately after the fetch request. But the statements following them will simply execute immediately without waiting for the new data. You need to listen to the reset
event or the sync event of the collection if you want the new data in hand. Also it is a better idea if you attach the common attributes
to the view directly using this
.. Try this
var VideosView = Backbone.View.extend({
tagName: 'ul',
id: 'video-list',
initialize: function () {
// Model
this.user = this.model;
// collection passed in
this.videos = this.collection;
// videos on model
this._videos = user.get('videos');
// filtered collection
this.user_vids = videos.filter_videos(this._videos);
// Listen to sync request on model
this.listenTo(user, 'sync', this.update);
// Listen to the video collection
// which will call the method once the collection is refreshed
this.listenTo(this.videos, 'reset', this.resetVideos);
},
update: function () {
$('#video-list').empty();
_.delay( function() {
// You already have access to videos
// in the form of this.videos
this.videos.fetch({reset: true});
}, 100 );
},
resetVideos: function () {
// Build the new user_vids collection from
// newly fetch videos collection
this.user_vids = this.videos.filter_videos(this._videos)
this.user_vids.each(this.addOne, this);
},
addOne: function (video) {
var videoView = new VideoView({
model: video
});
this.$el.append(videoView.render().el);
},
render: function () {
this.user_vids.each(this.addOne, this);
return this;
}
});
Let me know if the notes make sense or I misunderstood somewhere.
Upvotes: 2
Reputation: 2050
You should be listening to "sync" instead of "request"
request — when a model (or collection) has started a request to the server
sync — when a model (or collection) has been successfully synced with the server
by listening to request, you will only see the current data at the time of the request, not when the data has been synced and the collection updated.
Upvotes: 0