Update backbone View - javascript

I ve created a backbone model, which fetch json from a server. However, i want to update view with the new data, in specific time interval, not every time that the server sends data. What should i use with purpose to update backbone view every n milliseconds? I ve got the above code.
$(function() {
var Profile = Backbone.Model.extend();
var ProfileList = Backbone.Collection.extend({
model: Profile,
url: 'data.php'
});
var ProfileView = Backbone.View.extend({
el: "#profiles",
template: _.template($('#profileTemplate').html()),
render: function(eventName) {
_.each(this.model.models, function(profile){
var profileTemplate = this.template(profile.toJSON());
$(this.el).append(profileTemplate);
}, this);
return this;
}
});
var profiles = new ProfileList();
var profilesView = new ProfileView({model: profiles});
profiles.fetch({reset: true});
//profiles.bind('reset', function () { console.log(profiles); });
profiles.bind('reset', function () {
profilesView.render();
});
});

A simple solution would be:
profiles.fetch({reset: true});
setInterval(
function() {
profiles.fetch({reset: true});
}, 1000 // Time in milliseconds
);
I wouldn't say that it's a beautiful solution but I hope you get the idea. As far as I know there is no interval fetch, or something similar, implemented in Backbone - so you pretty much have to build your own.
EDIT
This is probably a better solution, I like it more atleast.
var ProfileList = Backbone.Collection.extend({
model : Profile,
url : "data.php",
xhr : null,
interval: null,
fetchWithInterval: function(options) {
var options = options || {},
self = this;
this.interval = setInterval(function(){
if(self.xhr !== null && self.xhr.readyState !== 4) {
return;
}
self.xhr = self.constructor.__super__.fetch.apply(self, options);
}, 1000);
this.xhr = self.constructor.__super__.fetch.apply(self, options);
},
stopFetchWithInterval: function() {
clearInterval(this.interval);
}
});
Use it with profiles.fetchWithInterval({reset: true}); and you can stop it with profiles.stopFetchWithInterval().
It also manages the xhr, so if the AJAX call isn't finished it will not start a new one. This is pretty handy if you want to fetch with a small interval or when your API is slow for some reason.

Related

Load Model From More Than One URL

How can I load different attributes for a model using different URLs?
E.g. I have 3 different and independent URLs that will return some attributes and I want to add all of those to a single model, suppose that I have the promise returned by all of them like this:
var model = //...
$.when(nameAttributes, addressAttributes, metaAttributes).then(
function(nameData, addressData, metaData) {
return _.extend({}, nameData, addressData, metaData);
})
.done(function(allData) {
model.set(allData);
doStuffWith(model);
});
Is there a way to turn that into this:
model.fetch().done(function(){ doStuffWith(model); });
Well.. Ok, this should do what you want. I STRONGLY suggest you do NOT take this route. Keep the data separately in individual Model()s that way you can update it and pull it when ever you need to. If you take this approach saving data will be a disaster.
http://jsfiddle.net/kjhvwxg4/
PS. I tried to not add any more code then i had to, keep in mind this will probably not handle error handling very well since xhr will never throw an error, you need to catch it yourself -- i didnt want to spend the time coding that since this is just a proof of concept.
var Model1 = Backbone.Model.extend({
fetch: function(options) {
options = _.extend({
parse: true
}, options);
var model = this;
var success = options.success;
var error = options.error;
options.success = function(resp) {
var serverAttrs = options.parse ? model.parse(resp, options) : resp;
if (!model.set(serverAttrs, options)) return false;
if (success) success.call(options.context, model, resp, options);
model.trigger('sync', model, resp, options);
};
options.error = function(resp) {
if (error) error.call(options.context, model, resp, options);
model.trigger('error', model, resp, options);
};
// custom code starts here
var call1 = $.getJSON('http://jsonplaceholder.typicode.com/posts/1');
var call2 = $.getJSON('http://jsonplaceholder.typicode.com/comments/2');
var call3 = $.getJSON('http://jsonplaceholder.typicode.com/albums/3');
var xhr = $.when(call1, call2, call3);
// mimics the same triggers the normal backbone does
model.trigger('request', model, xhr, options);
xhr.done(function(one, two, three){
var resp = _.extend(one[0], _.extend(two[0], _.extend(three[0], {})));
options.success(resp);
});
// we still need to send back an event handler
return xhr;
}
});
var model = new Model1();
model.fetch();
model.on('sync', function(model) {
alert(JSON.stringify(model.toJSON()));
});

Check if backbone has been fetched, or changed?

I need to have two url properties inside my Backbone.Collection.extend() because if a collection is fetched then I need to use a specific url if the collection gets a new model then I want to change the url
module.exports = MessagesCollection = Backbone.Collection.extend({
initialize: function(models, options) {
this.id = options.id;
},
url: function() {
if (fetch method is called) {
return '/api/messages/' + this.id;
} else {
// here if a model is being added?
return '/api/messages'
}
},
model: MessageModel
});
The reason for this is because I only want to pull down the models from the server based on the user.
var me = new MeModel();
me.fetch({
success: function(response) {
App.data.me = me;
var messages = new MessagesCollection([], { id: response.get('user_id') });
messages.fetch({
success: function() {
App.data.messages = messages;
App.core.vent.trigger('app:start');
}
});
}
});
When the user creates a new model within the app I want it to go into the main collection?
Does this mean I should create a sub collection based on the main collection somehow?
Edit:
My create looks like this somewhere else in the app window.App.data.messages.create(Message); I am thinking maybe I could write something like
var me = new MeModel();
me.fetch({
success: function(response) {
App.data.me = me;
var messages = new MessagesCollection([], { id: response.get('user_id') });
var allMessages = new MessagesCollection();
messages.fetch({
success: function() {
App.data.messages = messages;
App.data.allMessages = allMessages;
App.core.vent.trigger('app:start');
}
});
}
});
Then create window.App.data.allMessages.create(Message);> It sounds like it can cause problems IDK any ideas?
Edit:
The above worked but I had to create a new Backbone.Collection.extend() passing the same model but just writing it like
var Backbone = require('backbone'),
MessageModel = require('../models/message');
module.exports = AllMessagesCollection = Backbone.Collection.extend({
model: MessageModel,
url: '/api/messages'
});
So let me really break this question down, is this solution problematic. What is the best way to do this? The worst thing I can think of is bandwidth, using this method I would constantly be sending requests!
If you need to use different url only when create new model you can override collection.create method:
var MessagesCollection = Backbone.Collection.extend({
initialize: function(models, options) {
this.id = options.id;
},
url: function() {
return '/api/messages/' + this.id;
},
create: function(model, options){
var extendedOptions = _.extend(options || {}, {url: '/api/messages'});
return this.constructor.__super__.create.call(this, model, extendedOptions);
}
});

populate collection on Backbone

Tutorial.Views.Layout = Backbone.Layout.extend({
model: Tutorial.Model,
});
initialize: function () {
_.bindAll(this);
this.model = new Tutorial.Model({id : $("#data").data('user') });
this.collection = new Tutorial.Collection();
var success1 = function(){
console.log('OK');
};
this.collection.fetch({success : success1});
},
showTuto: function(){
step = this.collection.first(1);
console.log(step);
},
My problem is my collection is empty. My model has 4 items, but i see none of them .
Thanks in advance
We need to see some more code to make a closer suggestion, but hopefully this explanation will help you out. You should pass your model directly to the collection, OR deal with it in the fetch.
//simplified view
YourView = Backbone.View.extend({
initialize : function(){
var testModel = new Tutorial.Model({id : $("#data").data('user') });
this.collection = new Tutorial.Collection();
this.collection.add(testModel);
}
});
In this case, you would be adding that model directly to your collection. If you want to asyncronously call and get data from the fetch and then pass a callback, you could do something like this:
//simplified view
YourView = Backbone.View.extend({
initialize : function(){
this.collection = new Tutorial.Collection();
this.collection.fetch(function(){
console.log('okay');
});
}
});
Tutorial.Collection = Backbone.Collection.extend({
fetch : function(callback){
// grab a ref to your collection
var thisCollection = this;
// call your data function which has the ajax call
getYourDataFunction(function(data){
// if your data returned is an array of objects
thisCollection.add(data);
if (typeof callback === "function"){
//if you included a callback, call it with a reference to the collection
callback.call(thisCollection);
}
});
});
});

Problems with fetching and parsing using Backbone.js

I try to fetch this server: http://cshosting.webfactional.com/api/v1/projects/?format=json
to a backbone.js collection.
Then I try to console.log it, but it's not working.
It is very important to me, please help.
NEWS: I figured out it's something with JSONP. will be glad to hear more information about that. thanks.
this is parts of my code in short:
window.ProjectList = Backbone.Collection.extend({
model: Project,
url:"http://cshosting.webfactional.com/api/v1/projects",
parse: function(response) {
return response.objects;
}
});
another part:
window.HomeView = Backbone.View.extend({
initialize:function () {
this.projectList = new ProjectList();
this.projectList.fetch({success : function() {console.log(this.projectList); }});
this.homeListView = new HomeListView({model: this.projectList});
}
});
The this on the fetch callback is not going to refer to your HomeView instance. Try using another variable to ensure you are referencing the desired object.
initialize:function () {
var self = this;
this.projectList = new ProjectList();
this.projectList.fetch({success : function() {console.log(self.projectList); }});
this.homeListView = new HomeListView({model: this.projectList});
}
If that doesn't solve the problem, please describe what happens. Use the webkit inspector's network tab to make sure the correct GET request and response are being called. Make sure your parse function is being called and the response object is what you expect.
It seems like you would want to do something more like this:
window.Project = Backbone.Model.extend({
url:"http://cshosting.webfactional.com/api/v1/projects/?format=json"
});
window.ProjectList = Backbone.Collection.extend({
model: Project,
url:"http://cshosting.webfactional.com/api/v1/projects/?format=json"
});
window.HomeView = Backbone.View.extend({
initialize:function () {
_.bindAll(this, 'render');
},
render: function(){
var self = this;
console.log(self.collection);
return this;
}
});
var project = new Project();
var collection = new ProjectList();
collection.fetch({
success: function(result_collection, resp) {
var view = new HomeView ({ collection: result_collection });
view.render();
}
});

javascript should i delete?

I have some code like this:
var User = function () {
_.bindAll(this)
this.UserList = Backbone.Collection.extend({
model: UserModel
// ...
});
this.UserListView = Backbone.View.extend({
// ... etc
}
User.prototype.display = function() {
var self = this
self.collection = new self.UserList
self.collection.fetch({
success: function(collection, response) {
self.users = new self.UserListView({
collection: self.collection
});
}
})
};
var user = new User()
route("users", function () {
user.display()
})
My question is, is this going to cause memory issues? Every time the user arrives on the user/:userPage route the view, collection, etc are all going to be recreated. Will the old ones be deleted or do I have to delete it manually?
Should I be doing this:
User.prototype.display = function() {
var self = this
delete self.collection
self.collection = new self.UserList
self.collection.fetch({
success: function(collection, response) {
delete self.users
self.users = new self.UserListView({
collection: self.collection
});
}
})
};
Also other general advice on my example code is appreciated too.
This is utterly useless:
delete self.collection
self.collection = new self.UserList
All delete does is remove collection field from the self object, and then you immediately recreate it. Just do the assignment.
I think that you think that delete self.collection should somehow cause the garbage-collection of the object pointed to by the field. It doesn't.
Also, don't use self as a variable name. The browser uses it to mean, uh, something.

Categories

Resources