Angularjs promise wait for result - javascript

In my angularjs app I have the following code on button click:
if (!$scope.isChecked) {
$scope.getExistingName($scope.userName).then(function (data) {
$scope.userName = data;
});
}
//some processing code here then another promise
myService.save($scope.userName,otherparams).then(function (res) {
//route to page
}, function (err) {
});
The issue here is if $scope.isChecked is false, it goes inside the promise and since it takes time to resolve it comes out and goes to next line of code. Because of this $scope.userName is not updated and uses old values instead of the updated value returned.
Whats the best way to handle this?

You can use $q. First you have to inject $q in your angular controller.
//Create empty promise
var promise;
if (!$scope.isChecked) {
promise = $scope.getExistingName($scope.userName).then(function (data) {
$scope.userName = data;
});
}
// Wait or not for your promise result, depending if promise is undefined or not.
$q.all([promise]).then(function () {
//some processing code here then another promise
myService.save($scope.userName,otherparams).then(function (res) {
//route to page
}, function (err) {
});
});

If the myService.save need to wait for the $scope.getExistingName promise just compute that operation inside the "then" statement.
if (!$scope.isChecked) {
$scope.getExistingName($scope.userName).then(function (data) {
$scope.userName = data;
myService.save($scope.userName,otherparams).then(function (res) {
//route to page
}, function (err) {
});
});
}
//some processing code here then another promise

Related

How to reload a http.get request after performing a function

I am trying to delete a post from a list. The delete function is performing by passing serially to a delete function showed below.
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref)
.success(function (data) { });
}
After performing the function, I need to reload the http.get request which used for listing the list.
$http.get("api/phone_accept.php")
.then(function (response) { });
Once the function performed. The entire list will reload with new updated list. Is there any way to do this thing.
Try this
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref)
.success(function (data) {
//on success of first function it will call
$http.get("api/phone_accept.php")
.then(function (response) {
});
});
}
function list_data() {
$http.get("api/phone_accept.php")
.then(function (response) {
console.log('listing');
});
}
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref)
.success(function (data) {
// call function to do listing
list_data();
});
}
Like what #sudheesh Singanamalla says by calling the same http.get request again inside function resolved my problem.
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref).success(function (data) {
//same function goes here will solve the problem.
});}
});
You can use $q - A service that helps you run functions asynchronously, and use their return values (or exceptions) when they are done processing.
https://docs.angularjs.org/api/ng/service/$q
Inside some service.
app.factory('SomeService', function ($http, $q) {
return {
getData : function() {
// the $http API is based on the deferred/promise APIs exposed by the $q service
// so it returns a promise for us by default
return $http.get("api/phone_recev.php?id="+ref)
.then(function(response) {
if (typeof response.data === 'object') {
return response.data;
} else {
// invalid response
return $q.reject(response.data);
}
}, function(response) {
// something went wrong
return $q.reject(response.data);
});
}
};
});
function somewhere in controller
var makePromiseWithData = function() {
// This service's function returns a promise, but we'll deal with that shortly
SomeService.getData()
// then() called when gets back
.then(function(data) {
// promise fulfilled
// something
}, function(error) {
// promise rejected, could log the error with: console.log('error', error);
//some code
});
};

$timeout wrapping $http.post return undefined instead of promise

I'm trying to submit a form that require that the user email is not duplicated, but I want to make an small animation before the POST request. In the $scope.process function I'm getting:
TypeError: Cannot read property 'catch' of undefined.
That's happening because $scope.process is returning before the $http.post is complete, but how can I make process() return the promise instead of undefined?
So, this is what I have so far:
//The submit form function
$scope.submitForm = function () {
$('.btn').attr('disable');
if ($scope.form.$valid) {
$scope.process($scope.account)
.catch(function (err) {
if (err.code === 'duplicate') {
// handle error
}
});
return false;
}
};
//This is the one in charge to send the request
$scope.process = function(body) {
// Timeout before http post to wait for animation
$timeout(function() {
return $http.post(postUrl, body).then(function (response) {
// This return a promise if I remove the $timeout
var nextPage = response.data;
}).catch(function (err) {
throw err;
});
}, 300);
// Return undefined due to $timeout
};
Thanks in advance.
You were getting TypeError: Cannot read property 'catch' of undefined, because you weren't returning promise from process function at all.
Do return $timeout promise from process function & apply .then & .catch over $timeout promise object.
By returning $timeout service the inner $http.post will return a data, so that will make proper chaining mechanism.
Code
$scope.process = function(body) {
// returned promise from here
return $timeout(function() {
//returned $http promise from here.
return $http.post(postUrl, body).then(function (response) {
// This return a promise if I remove the $timeout
nextPage = response.data;
return nextPage; //return data from here will return data from promise.
}).catch(function (err) {
throw err;
});
}, 300);
};

angular js validate JSON from server

as I understand it Angular http has 2 checks 'success and 'error'. Thats in terms of connecting to the service or not - so I have that in hand and thats my first check.
The issue I have is that the data in my JSON has a success state which informs me if the data it contains or has received from my form had any problems with it, in which case there will be an error object that I act on and display to the user.
I need to check for that value of success, but where is the best place to check for that?
Should I be doing it in the controller?
Without that data being correct theres nothing else for the page to do so it is effectively the first thing that needs to be done after the data is retrieved.
heres the basic controller layout
app.controller("dataCtrl", function ($scope, $http) {
$http.post('/getdata').success(function (data) {
$scope.businessData = data;
// Should I then be checking businessData.success at this level?
}).error(function () {
alert("Problem");
});
});
You can write something like this:
$http.post('/getdata').success(function (data) {
if (validate(data)) {
$scope.businessData = data;
} else {
$scop.buisnessDataError = {msg: 'smth bad happend'};
}
}).error(function () {..})
Otherwise, you can write your validator in Promise-like style and then just chain promises in such manner:
$http.post('/getdata').then(function (res) {
return validator(null, res.data);
}, function (err) {
return validator({msg: 'error'})
}).then(function (data) {
//proceed your data
}, function (err) {
alert(err.msg);
});
Where validator is:
var varlidator = function (err, data) {
return $q(function (resolve, reject) {
if (/*data is not valid*/ || err) {
reject(err);
} else {
resolve(data);
}
});
}
$q is a standard angulars implementation of Promises

pass data from a service to controller

i have a factory am passing it to controller LoginCtrl
.factory('Fbdata', function(){
var service = {
data: {
apiData: []
},
login: function () {
facebookConnectPlugin.login(["email"],
function() {
facebookConnectPlugin.api("me/?fields=id,email,name,picture", ["public_info","user_birthday"],
function (results) {
service.data.apiData = results;
console.log(service.data.apiData);
return results;
},
function (error) {
console.error('FB:API', error);
});
},
function(err) {
console.error('FB:Login', err);
});
}
};
return service;
})
LoginCtrl:
.controller('LoginCtrl', function($scope, Fbdata){
$scope.login = function(){
if (!window.cordova) {
var appId = "appId";
facebookConnectPlugin.browserInit(appId);
}
$scope.loginData = Fbdata.login();
console.log(Fbdata.data.apiData);
// got empty array []
$scope.retVal= angular.copy(Fbdata.data.apiData);
};
})
the Fbdata.data.apiData return empty array and i only could see the returned data from the login success function in the console .
my template which is has LoginCtrl as controller:
<div class="event listening button" ng-click="login();">Login with Facebook</div>
<h2>{{loginData.name}}</h2>
<h2>{{retVal.name}}</h2>
There is a variety of ways to achieve this, example:
Now I have never used Cordova Facebook Plugin so I'm not sure if you need to run the api function after the log in, or how those procedures need to be ordered. But I wanted to show you an example of how to retrieve the data from the factory using your code sample. Hope that helps
Edit 2:
I have changed my code to using promises that way we make sure that we don't call one without the other being completed, I am not a fan of chaining the login and api functions within one function since it is possible(?) that you may need to call login() but don't want to call api(), please try my code and paste in your console logs in the bottom of your question.
Factory:
// Let's add promises to our factory using AngularJS $q
.factory('Fbdata', ['$q', function($q){
// You could also just replace `var service =` with `return` but I thought this
// would make it easier to understand whats going on here.
var service = {
// I generally nest result to keep it clean when I log
// So results from functions that retrieve results are stored here
data: {
login: [],
api: []
},
api: function() {
var q = $q.defer();
facebookConnectPlugin.api("me/?fields=id,email,name,picture", ["public_info","user_birthday"],
function (results) {
// assign to the object being returned
service.data.api = results;
// The data has returned successfully so we will resolve our promise
q.resolve(results);
},
function (error) {
// We reject here so we can inform the user within through the error/reject callback
q.reject(error);
console.error('FB:API', error);
});
// Now that we have either resolved or rejected based on what we received
// we will return the promise
return q.promise;
},
login: function () {
var q = $q.defer();
facebookConnectPlugin.login(["email"], function (results) {
// assign to the object being returned
service.data.login = results;
q.resolve(results);
}, function(err) {
q.reject(error);
console.error('FB:Login', err);
});
return q.promise;
}
};
return service;
}])
Controller:
.controller('LoginCtrl', function($scope, Fbdata){
$scope.login = function(){
if (!window.cordova) {
var appId = "appid";
facebookConnectPlugin.browserInit(appId);
}
// By using the promises in our factory be can ensure that API is called after
// login by doing the following
// then(success, reject) function allows us to say once we have a return, do this.
Fbdata.login().then(function () {
$scope.loginData = Fbdata.data.login;
// Check what was returned
console.log('loginData', $scope.loginData);
Fbdata.api().then(function () {
$scope.apiData = Fbdata.data.api;
console.log('apiData', $scope.apiData);
}, function () {
// Tell the user that the api failed, if necessary
});
}, function () {
// Tell the user that the log in failed
});
};
});

Promise not working properly in loop

Promise is not working properly saveService is called before promise resolved means all documents get uploaded, but when I log the data in the saveService it shows the uploaded docs unable to figure out the issue, please let me know where i am wrong
//file upload
$scope.fileObj = {};
$scope.documentUploaded = [];
var uploadFile = function (type) {
var file = $scope.fileObj[type];
//service to upload file
fileService.uploadDocument(file)
.success(function (data, status) {
console.log("uploaded successfully", data);
$scope.documentUploaded.push({
doc: {
fileName: data.name,
path: data.path
}
});
})
.error(function (data, status) {
});
}
$scope.save = function () { //on click of submit, save() is called
var defer = $q.defer();
var promises = [];
//looping to upload files
angular.forEach($scope.documentList, function (doc) {
if ($scope.fileObj[doc.type]) {
promises.push(uploadFile(doc.type));
}
});
//this will save data when promise will get complete
var saveData = function () {
var dataToSave = {
//other fields
documents: $scope.documentUploaded
};
saveService.saveApi(dataToSave)
.success(function () {
defer.resolve('data saved');
})
.error(function () {
defer.reject("something went wrong");
});
}
$q.all(promises).then(saveData);
return defer;
}
uploadFile() needs to return a promise (that is resolved when its work is done) for $q.all(promises) to work.
Right now it isn't returning anything so you're passing $q.all() an array of undefined values. Since there are no promises in that array, $q.all() executes the .then() handler immediately.
Here's a condensed version of the problem:
var promises = [];
...forEach(function() {
promises.push(uploadFile(doc.type));
});
$q.all(promises).then(saveData);
So, you're pushing into the promises array the return value from uploadFile(). But uploadFile() doesn't even return anything. So, you're pushing in undefined. Then, you pass an array of undefined values to $q.all when it's expecting an array of promises.
So, to make this logic work, you need uploadFile() to return a promise that gets resolved when that instance of uploadfile() is done with its async work.
If fileService.uploadDocument() already returns a promise, you can just return that promise. If not, then you can create one at the beginning of uploadFile() and return it at the end and then resolve or reject it in the .success() and .error() handlers.
If fileService.uploadDocument() can already make a promise, then the preferred solution would be to use that promise (I don't know that API so don't know how it works). If it can't make a promise, then you can make your own like this:
var uploadFile = function (type) {
var defer = $q.defer();
var file = $scope.fileObj[type];
//service to upload file
fileService.uploadDocument(file)
.success(function (data, status) {
console.log("uploaded successfully", data);
$scope.documentUploaded.push({
doc: {
fileName: data.name,
path: data.path
}
});
defer.resolve();
})
.error(function (data, status) {
defer.reject();
});
return defer.promise;
}

Categories