How to stop fetching collections in backbone - backbone.js

Disk is my collections object. I need to stop fetching collections
customPoll: function(time){
var set_time = 0;
if(time === undefined){
set_time = 4000;
}
var route = Backbone.history.fragment.split('/');
var self = this;
if(route[0] === "disks"){
setTimeout(function() {
Disks.fetch({update:true,success: function(){
self.customPoll();
}, error: function(){
self.customPoll();
}
});
}, set_time); //TODO Need to handle efficiently...
}
}
Am trying to call this fetching in every 4 second if some condition exist other wise i need to stop calling this fetching.
var route = Backbone.history.fragment.split('/');
var smart = new Smart.model({
"id" : route[1]
});
var self = this;
smart.save(null,{
success: function(model,event,response){
model = Disks.get(route[1]).toJSON();
$('#smart-confirm-dialog').modal('hide');
self.showStatusMsg(1,"<b> S.M.A.R.T. Test : </b>S.M.A.R.T Test started succesfully");
if(model.smart.progress === "100%"){
self.clearAllTimeout();
alert("please stop fetching....pleaseeee");
// Stop polling here . then fetch information from smart.fetch api.
Smart.fetch({update: true}); //this is another api i need to call this api now.
}else{
self.customPoll();
}
});
But it seems to be not working... Its keep on fetching collection.. How can i stop this Disk collection fetching.

My answer maybe is funny, I want to add comment, but I couldn't. can you add new field to your model and
customPoll: function(time){
var disks = this.model.toJSON();
if(disks.yourField){
// here your code
}
}
but before saving the model need to do delete disks.yourField;

Related

Sort firebase object based on time stamp

I am developing chat application using Firebase. In my chat application i have chat Inbox.I need to sort the inbox chat based on time stamp.
To load the object from Firebase i am using following code:
var chatwith = new Firebase(firbaseUrl+'/chatInbox/'+$scope.userId);
var list = $firebaseArray(chatwith);
list.$loaded().then(function() {
$scope.dataList = list;
$scope.dataLength = $scope.dataList.length;
if (!$scope.$$phase) $scope.$apply();
});
I need to sort the $scope.dataList object based on the time stamp. is it possible?
Please suggest
to answer your question
I need to sort the $scope.dataList object based on the time stamp. is it possible?
yes it's possible , you could use orderByChild like this
var chatwith = new Firebase(firbaseUrl+'/chatInbox/'+$scope.userId);
chatwith = chatwith.orderByChild('NAME_OF_THE_FIELD_TIMESTAMP');
var list = $firebaseArray(chatwith);
list.$loaded().then(function() {
$scope.dataList = list;
$scope.dataLength = $scope.dataList.length;
if (!$scope.$$phase) $scope.$apply();
});
just don't forget to Defin Data Indexes on production like this
{
"rules": {
"chatInbox": {
".indexOn": ["NAME_OF_THE_FIELD_TIMESTAMP", "OTHER_FIELD"]
}
}
}

Angular - update services object during asynchronous function

Folks: Creating an app in angular and node webkit - where users queue up files for downloading, navigate to their dashboard view and this initiates the downloads.
I've created a service which holds an object of the files data:
..
var downloadObj = {};
// fileObj = {'name':'The file name'; 'download_progress' : dlProgress}
showcaseFactory.myDownloads = function(eventId, fileObj) {
if(eventId){
console.log('update the object');
downloadObj['event_'+eventId] = fileObj;
}
console.log(downloadObj);
};
showcaseFactory.getDownloads = function() {
return downloadObj;
};
..
When the dashboard view loads - ng-repeat loops over $scope.downloadFiles which references this object returning the data.
<div ng-repeat="file in downloadFiles">
<div><span>{{file.name}}</span> [{{file.download_progress}}%]</div>
</div>
I've created a custom module which utilises node_modules to perform the download of the files:
nwjsDownloadFactory.commenceDownload = function(event_id, url, dest, cb) {
var http = require('http');
var fs = require('fs');
var statusBar = require('status-bar');
var path = require('path');
// THIS UPDATES THE OBJECT AND DISPLAYS FINE --------- >>
var id = 7;
var testFileObj = {
'name' : 'This is the file name prior to the download...',
'download_progress' : 10
};
ShowCase.myDownloads(id, testFileObj);
// <<< THIS UPDATES THE OBJECT AND DISPLAYS FINE ---------
var file = fs.createWriteStream(dest);
var request = http.get(url, function(response) {
response.pipe(file);
file.on('finish', function() {
file.close(cb); // close() is async, call cb after close completes.
});
bar = statusBar.create({ total: response.headers['content-length'] })
.on('render', function (stats) {
// var percentage = this.format.percentage(stats.percentage);
// console.log(event_id + '....' + percentage);
var id = 7;
var testFileObj = {
'name' : 'This is the new file name during the download...',
'download_progress' : 35 // this will be replaced with percentage
};
ShowCase.myDownloads(id, testFileObj);
});
response.pipe(bar);
}).on('error', function(err) { // Handle errors
fs.unlink(dest); // Delete the file async. (But we don't check the result)
if (cb) cb(err.message);
});
}
QUESTION: Prior to the line var request = http.get(url, function(response) the object gets updated, and the changes are reflected in the UI. However, I need to constantly update the object with download complete % so I can create a progress bar.. However, as this asynchronous function executes, the object
appears to be updating - see the attached screen shot - but the UI is not reflecting this.
Can somebody please steer me in the right direction - I need the object to update during the function bar = statusBar.create({ and for the changes to reflect in the UI..
Call $scope.$apply() after making changes to your model to notify Angular that it has to update the UI.
showcaseFactory.myDownloads = function(eventId, fileObj) {
if(eventId){
console.log('update the object');
downloadObj['event_'+eventId] = fileObj;
$scope.$apply();
}
console.log(downloadObj);
};
If you use Angular's $http object, this is handled automatically for you, but if you update your model from other asynchronous callbacks, you have to take care of it yourself.
See this blog post and this documentation page for more in-depth explanations about what's going on.

How to roll back changes when there is an error in a promise chain

In my angular app I want to make changes to several locations in my firebase with a mix of transactions and set. I have written a promise chain with a little help. Now I need to handle any errors that may occur.
In the event of an error on any of the promises I would want to roll back any changes made in firebase (the successful promises) and alert the user to the failure.
Current code below
$scope.addNewPost = function() {
var refPosts = new Firebase(FBURL).child('/posts').push();
// Get tags into array for incrementing counters
var tags = $scope.post.tags.split(', ');
var allPromises = [];
// Iterate through tags and set promises for transactions to increment tag count
angular.forEach(tags, function(value, index){
var dfd = $q.defer();
var refTag = new Firebase(FBURL).child('/tags/' + value);
refTag.transaction( function (current_value) {
return current_value + 1;
}, function(error, committed, snapshot) {
if (committed) {
dfd.resolve( snapshot );
} else {
dfd.reject( error );
}
});
allPromises.push( dfd.promise );
});
// Add promise for setting the post data
var dfd = $q.defer();
refPosts.set( $scope.post, function (error) {
if (error) {
dfd.reject(error);
} else {
dfd.resolve('post recorded');
}
});
allPromises.push( dfd.promise );
$q.all( allPromises ).then(
function () {
$scope.reset(); // or redirect to post
},
function (error) {
// error handling goes here how would I
// roll back any data written to firebase
alert('Error: something went wrong your post has not been created.');
}
);
};
So what I need to know is how do I roll back any changes that happen to my firebase data in the event that one of these promises fail. There could be any number of updates happening in firebase. (for example: 3 tags being incremented via transaction and the post data being set)
How would I write the failure function to calculate what was successful and undo it? If this is this even possible.
--------------- sub question from original post has been solved ---------------
Also how do you force errors? I've tried setting a variable like below but it doesn't seem to work, is there something wrong with my .then?
refPosts.set( $scope.post, function (error) {
var forceError = true;
if (forceError) {
dfd.reject(forceError);
} else {
dfd.resolve('post recorded');
}
allPromises.push( dfd.promise );
});
There are two instances of this line, and they are both in the wrong place:
allPromises.push( dfd.promise );
In the first block, it should be in the last statement in the forEach callback, not in the transaction callback.
In the second block, it should be after the call to set(), not in the callback.
The way your code is written now, $q.all() is getting an empty array of promises. That could also be what's interfering with the forceError test you're attempting.

Backbone.js parse for saving

I have a model which keeps some other models in an attribute array. When these models are stored, however, I don't want to keep the sub-modules around--instead, I want to store the primary keys, and then when the model is fetched from the server, its parse will "reconstitute" them by fetching the related models.
What is the best approach to accomplishing this? The closest I've come to getting it to work is overriding the sync method:
sync : function(method, model, options) {
var topics = this.get('topics');
model.attributes.topics = _.pluck(topics, 'id');
var ret = Backbone.Model.prototype.sync.call(this, method, model, options);
this.attributes.topics = topics;
return ret;
},
but this regularly fails, leaving the keys in the attributes instead of the full models & consequently crashing.
Parse function (slightly paraphrased):
parse : function(response) {
response.topics = _.map(response.topics, function(item) {
return app.topics.getByPK(item);
}
return response;
}
What I would do would be something more along these lines:
parse : function(response) {
this.topics = _.map(response.topics, function(item) {
return app.topics.getByPK(item);
}
return response;
}
Which keeps your array of ids intact at all times, and you have access by using this.topics instead of this.get('topics') or this.attributes.topics

Backbone collection.create not creating the model locally

I gave up finally. I have struggling to get this one to work but no luck. I simply have a collection.create call like this:
var createData = {
full_name : full_name,
email : email,
role_id : role_id
};
var that = this;
app.collections.teamMembers.create(createData,{
wait: true,
success : function(){
log("in success")
},
error : function(a,b,c){
log("in error")
}
})
The server is PHP and it returns the result like this:
header('Content-type: application/json');
echo json_encode(array(
"data" => $data,
"meta" => $meta
));
In the above, the $data is actually the array("attr"=>"val", ...) which matches exactly how the model for this collection is defined.
The problem is that since I am not returning directly a JSON object similar to the original model, but using namespacing (data/meta), I use model.parse on the model like this:
parse : function(response){
log(response, "inside model parse, this is the response from server")
return response.data;
},
ISSUE: The model doesn't get created on the client end. No 'add' event is fired. I am also using the wait:true option.
However, the model gets created on the local if:
- I don't use wait:true
- I use wait true but return the exact JSON model from server, with no name spacing.
I WANT to use wait:true as well as namespacing. Please help :(
Finally I was able to fix it, I was overriding backbone collections and models in my bootstrap to have a loading state which I am not using anyway. So I commented out that whole code. Now it works fine. this was the code in my bootstrap that I commented out:
// OVERRIDINGS AND SETTINGS
//----------------------
// Adding close method to all views
Backbone.View.prototype.close = function() {
if (this.onClose) {
this.onClose();
}
_.each(this.childViews, function(childView){
childView.close();
delete childView;
})
this.remove();
this.unbind();
};
// Adding loading state to every model and collection
Backbone.Collection.prototype.loading = false;
Backbone.Model.prototype.isLoading = false;
// Set isLoading to true when fetch starts
var oldFetch = Backbone.Collection.prototype.fetch;
Backbone.Collection.prototype.fetch = function(options) {
this.isLoading = true;
oldFetch.call(this, options);
}
Backbone.Model.prototype.fetch = function(options) {
this.isLoading = true;
oldFetch.call(this, options);
}
// Turn off isLoading when reset
Backbone.Collection.prototype.on('reset', function(){
this.isLoading = false;
})
Backbone.Model.prototype.on('reset', function(){
this.isLoading = false;
})

Resources