Synchronize call back in Angular JS - javascript

I am trying synchronize two call backs one from service and one directly called . (This is old code so please ignore code quality)
if($scope.newUser.password == $scope.newUser.password2)
{
// search for the user to see if it already exists
UserValidateService.findUserByEmail($scope.newUser.username, $scope.newUser.email, function(user){
console.log(user);
if(user[0]) {
alert('email Id already exists ******');
return false;
}
}).then(function(){
$http.get("/api/user/"+$scope.newUser.username)
.success(function(newUser) {
// if user does not exist, create it new
if(newUser.length == 0) {
$http.post("/api/user", $scope.newUser)
.success(function(newUser){
if(newUser == null)
alert("Unable to register user");
else
$location.path( $scope.newUser.username+"/home" );
});
}
else
{
alert("User already exists");
}
});
});
}
else
{
alert("Passwords must match. Try again");
}
Service :
app.factory('UserValidateService', function($http){
var findUserByEmail = function (user, email, callback) {
$http.get("/api/user/"+user+"/email/"+email)
.success(callback);
};
return {
findUserByEmail: findUserByEmail
};
});
Error:
TypeError: Cannot read property 'then' of undefined
at h.$scope.register (user.js:118)
at angular.js:10567
at angular.js:18627
at h.$eval (angular.js:12412)
at h.$apply (angular.js:12510)
at HTMLButtonElement.<anonymous> (angular.js:18626)
at HTMLButtonElement.jQuery.event.dispatch (jquery.js:5095)
at HTMLButtonElement.elemData.handle (jquery.js:4766)
Can any please let me where I am going wrong or how to make this code synchronize i.e calling

Your UserValidateService doesn't return a promise, it uses a callback from the $http success method. This is an anti-pattern that should be avoided.
Convert your factory to return the promise from the $http service:
app.factory('UserValidateService', function($http){
var findUserByEmail = function (user, email) {
return $http.get("/api/user/"+user+"/email/"+email)
};
return {
findUserByEmail: findUserByEmail
};
});
Then use the .then method of the promise to execute the callback functionality.
var promise = UserValidateService
.findUserByEmail($scope.newUser.username,
$scope.newUser.email);
var derivedPromise = promise.then ( function(response){
console.log(response.user);
if(response.user[0]) {
alert('email Id already exists ******');
});
//return response for chaining
return response;
});
Subsequent actions can chain off the derivedPromise.

Related

Promise handling - update db entry if exists

I am stuck with new challenge on Promises.
Goal: Update the DB entry only if P_KEY exists.
current db is exposed through module and module has get and put method for db. Both returning Promise.
Approach:
API calls for update method handler on node js with ID and Set of values (json)
In handler for post method call to get method of db module check if value on promise success is empty or not if yes return false else true.
If true; data exists call to put method of db module.
but somehow data it always returns false. even if db entry has been made through db api.
/** Function to check if p_key exist*/
function checkIfPKExists(idVal){
pkdb.get(idVal).then(function(value){
if(value){
return true;
} else {
return false;
}
},
function(err){
console.log(err);
return false;
})
}
/** UPDATE METHOD **/
var ch = checkIfPKExists("p_k"+req.body.id);
if(!ch){
res.send("pk does not exist oo " + req.body.id);
} else {
var pk_promise = pkdb.put("p_k"+req.body.id, req.body.pk);
pk_promise.then(
function(){
res.send(JSON.stringify(req.body.pk) + "Updated Successfully");
},
function(err){
res.send("Error occurred : " + err);
}
)
}
My understanding is ch value is set from checkPK function and since thats a promise it just goes ahead and processes if loop which by default stands true and done irrespective whether element is there or not same result. Not found.
What can I do to correct it?
One issue is that no value is returned from checkIfPKExists() function call, see Why is value undefined at .then() chained to Promise?. Use .then() and .catch() to get the Promise value returned from the function
function checkIfPKExists(idVal) {
// `return` the `Promise` here
return pkdb.get(idVal).then(function(value) {
if (value) {
return true;
} else {
return false;
}
}, function(err) {
console.log(err);
return false;
})
}
/** UPDATE METHOD **/
var ch = checkIfPKExists("p_k" + req.body.id);
ch.then(function(bool) {
// if `true` do stuff
if (bool) {
var pk_promise = pkdb.put("p_k" + req.body.id, req.body.pk)
return pk_promise.then(function() {
return res.send(JSON.stringify(req.body.pk) + "Updated Successfully");
}, function(err) {
return res.send("Error occurred : " + err);
})
} else {
// do other stuff
return res.send("pk does not exist oo " + req.body.id);
})
.catch(function(err) {
// handle error
})
checkIfPKExists() is an asynchronous function, if you want to use ch you would have to use a .then() to get it in a function and then use the value.
function checkIfPKExists(idVal)
{
return pkdb.get(idVal).then(function(value)
{
if(value)
{
return true;}
else
{
return false;
}
}, function(err)
{ console.log(err);
return false;
})
}
/** UPDATE METHOD **/
checkIfPKExists("p_k"+req.body.id).then(function(ch){
if(!ch)
{
res.send("pk does not exist oo " + req.body.id);
}
else
{
return pkdb.put("p_k"+req.body.id, req.body.pk).then(
function()
{
res.send(JSON.stringify(req.body.pk) + "Updated Successfully");
},
function(err)
{
res.send("Error occurred : " + err);
})
}})

NodeJS Async: callback allready called?

I am getting this error:
node:19100) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Callback was already called.
On my async.each call, it seems like it is trying to call "done()" more then once per "circuit" but I don't understand why, i though that once the async callback is called the function would exit ?
Circuits is an array of String containing ids. I am simply trying to loop through them to execute async calls to database on each.
var getTimeseriesForCircuit = function(circuits, to, from, callback){
if (!validateDates(from, to)) {
return callback(400, 'Invalid date(s)');
}
var validJSON = false;
try {
circuits = JSON.parse(circuits);
validJSON = true;
}
catch (e) {
return callback(500, e);
}
if (validJSON) {
async.each(circuits, function (circuitID, done) {
var frequency = getFrequencyFromRange(from, to);
var influxFromDate = from * 1000000;
var influxToDate = to * 1000000;
getVoltageGatewayID(null, circuitID, function (gatewayID) {
getVoltageFromInflux(null, influxFromDate, influxToDate, gatewayID, frequency, function (voltage) {
getMeanAmpsFromInflux(null, influxFromDate, influxToDate, circuitID, frequency, function (data) {
if (JSON.stringify(data) != []) {
var timeWithPower = calculatePower(data, voltage);
return done(null, {'circuitID': circuitID, data: timeWithPower});
}
});
});
});
}, function (err, results) {
if (err) {
return callback(500, err)
} else {
return callback(200, results)
}
});
}
else {
return callback(400, 'The circuits sent were not in a valid format');
}
}
I think you have to call your async callback "done" without return:
done(null, {'circuitID': circuitID, data: timeWithPower});
and on error something like this:
done('errormessage');
so you get your result in the "final"callback after your each
see async
I think you missing return statement in function.
When you catch or have an error instead of just callback() use return callback().
This will prevent execution of code bellow return statements and error that you see.
Hope this helps.

AngularJS resolve promise before load route

I'm trying to make promise inside a factory and then validate in locationChangeStart. The problem is that the locationChangeStart doesn't wait for my promise. What can I do to make my promise wait to complete?
Here is my code,
app.run(['$rootScope','$location','KeyFactory',
function($root, $location,KeyFactory) {
$root.$on('$locationChangeStart', function(event, curr, prev) {
KeyFactory.check();
console.log(KeyFactory.GetKeyPass()); ///PRINT undefined
if(KeyFactory.GetKeyPass()== true){
console.log('authorised');
}else{
$location.path('/login');
}
});
}]);
app.factory('KeyFactory', ['$http','$log', function($http,$log) {
var key = {};
key.setKeyPass = function(set) {
key.Status = set;
}
key.GetKeyPass = function() {
return key.Status;
}
key.check = function(){
$http.post('http://localhost/api/CheckPass').success(function(data) {
console.log(data);
key.setKeyPass(true);
}).error(function (data, status){
$log.error("error you cant acess here!");
console.log(status);
});
}
return key;
}]);
Asynchronous code doesn't work in synchronous way as you are thinking. After making an ajax it doesn't respond in the next line. In angular after making an ajax it return an promise object which is responsible to tell that response/error is going to happen.
There are couple of things missing in your code.
You should return a promise from the check method of service.
Then put .then function on check method promise & expect response in its success/error callback.
Code
key.check = function(){
return $http.post('http://localhost/api/CheckPass').then(function(response) {
var data = response.data;
key.setKeyPass(true);
}, function (response){
key.setKeyPass(false);
});
Run
KeyFactory.check().then(function(){
if(KeyFactory.GetKeyPass()== true){
console.log('authorised');
}else{
$location.path('/login');
}
});

How to make synchronous call in Angular JS?

The following code supposed to be update username in the data base then retrieve updated username.
updateUserMame and getUserName are two different REST calls.
updateName(name) {
var obj = this;
if (name === 'None') {
name = null;
}
obj.UtilityService.updateUserName(name, obj.userId)
.success(function (data) {
if (data) {
obj.getUserName(obj.userId);
console.log('Name is updated for ID:'||obj.userId);
} else {
console.log('Something Wrong');
}
});
}
getUserName(userId){
obj.UtilityService.getUserName(userId)
.then(function (result) {
console.log(result.user.userId);
}
}
I have user name 'Nathan Drake' in the dataBase.
When I run the update function with 'Elena Fisher', it is returning 'Nathan Drake'.
I've read some articles to make synchronus service calls, but unable to figure out what is going wrong.
Please help.
You could wrap your update function in a promise:
var updatePromise = $q.when(updateName(name)); // creates a promise
When your promise has finished processing, you can resolve it using then() which takes a success callback and an error callback
updatePromise().then(function successCallback(response){ // resolves the promise using then
getUserName(userId) // execute the rest of your code
},
function errorCallback(response){
console.log(error)
});
You would need to inject $q into the scope you are working with
Your code does not make much sense, that is I see possible mistakes as it looks like you are interchanging user name and user id and calling the obj context from inside a function even when its not declared there etc. Either we are missing code or this will fail when you try to run it.
Here is your example with some fixes and comments that show how you could do it using callbacks (no sync code, as mentioned by everyone else on this thread you should avoid actually waiting for I/O and use callbacks instead).
updateName(name) {
var obj = this; // good, you captured this
if (name === 'None') {
name = null;
}
obj.UtilityService.updateUserName(name, obj.userId)
.success(function (data) {
if (data) {
// ok, you successfully updated the name so why would you go back to the server and get it again? You know the value based on your update.
console.log('Name is updated for ID:' + obj.userId.toString());
// for your example though here is how you could handle it
obj.getUserName(obj, obj.userId, function(user){ // i assumed the name is stored in variable userName
console.log('Name from server = ' + user.userName); // no idea what you are returning but you can figure it out from here
// maybe you also want to capture it again??
obj.name = user.userName;
});
} else {
console.log('Something Wrong');
}
});
}
// pass in captured this as obj, the user id, and a callback
getUserName(obj, userId, callback){
obj.UtilityService.getUserName(userId)
.then(function (result) {
callback(result); // call the callback with the result. The caller can then do something with it
}
}

Global Error handler that only catches "unhandled" promises

I have a global error handler for my angular app which is written as an $http interceptor, but I'd like to take it a step further. What I'd like is for each $http call that fails (is rejected), any "chained" consumers of the promise should first try to resolve the error, and if it is STILL unresolved (not caught), THEN I'd like the global error handler to take over.
Use case is, my global error handler shows a growl "alert box" at the top of the screen. But I have a couple of modals that pop up, and I handle the errors explicitly there, showing an error message in the modal itself. So, essentially, this modal controller should mark the rejected promise as "handled". But since the interceptor always seems to be the first to run on an $http error, I can't figure out a way to do it.
Here is my interceptor code:
angular.module("globalErrors", ['angular-growl', 'ngAnimate'])
.factory("myHttpInterceptor", ['$q', '$log', '$location', '$rootScope', 'growl', 'growlMessages',
function ($q, $log, $location, $rootScope, growl, growlMessages) {
var numLoading = 0;
return {
request: function (config) {
if (config.showLoader !== false) {
numLoading++;
$rootScope.loading = true;
}
return config || $q.when(config)
},
response: function (response) {
if (response.config.showLoader !== false) {
numLoading--;
$rootScope.loading = numLoading > 0;
}
if(growlMessages.getAllMessages().length) { // clear messages on next success XHR
growlMessages.destroyAllMessages();
}
return response || $q.when(response);
},
responseError: function (rejection) {
//$log.debug("error with status " + rejection.status + " and data: " + rejection.data['message']);
numLoading--;
$rootScope.loading = numLoading > 0;
switch (rejection.status) {
case 401:
document.location = "/auth/login";
growl.error("You are not logged in!");
break;
case 403:
growl.error("You don't have the right to do this: " + rejection.data);
break;
case 0:
growl.error("No connection, internet is down?");
break;
default:
if(!rejection.handled) {
if (rejection.data && rejection.data['message']) {
var mes = rejection.data['message'];
if (rejection.data.errors) {
for (var k in rejection.data.errors) {
mes += "<br/>" + rejection.data.errors[k];
}
}
growl.error("" + mes);
} else {
growl.error("There was an unknown error processing your request");
}
}
break;
}
return $q.reject(rejection);
}
};
}]).config(function ($provide, $httpProvider) {
return $httpProvider.interceptors.push('myHttpInterceptor');
})
This is rough code of how I'd expect the modal promise call to look like:
$http.get('/some/url').then(function(c) {
$uibModalInstance.close(c);
}, function(resp) {
if(resp.data.errors) {
$scope.errors = resp.data.errors;
resp.handled = true;
return resp;
}
});
1. Solution (hacky way)
You can do that by creating a service doing that for you. Because promises are chain-able and you basically mark a property handled at the controller level, you should pass this promise to your service and it'll take care of the unhandled errors.
myService.check(
$http.get('url/to/the/endpoint')
.then( succCallback, errorCallback)
);
2. Solution (preferred way)
Or the better solution would be to create a wrapper for $http and do something like this:
myhttp.get('url/to/the/endpoint', successCallback, failedCallback);
function successCallback(){ ... }
function failedCallback(resp){
//optional solution, you can even say resp.handled = true
myhttp.setAsHandled(resp);
//do not forget to reject here, otherwise the chained promise will be recognised as a resolved promise.
$q.reject(resp);
}
Here the myhttp service call will apply the given success and failed callbacks and then it can chain his own faild callback and check if the handled property is true or false.
The myhttp service implementation (updated, added setAsHandled function which is just optional but it's a nicer solution since it keeps everything in one place (the attribute 'handled' easily changeable and in one place):
function myhttp($http){
var service = this;
service.setAsHandled = setAsHandled;
service.get = get;
function setAsHandled(resp){
resp.handled = true;
}
function get(url, successHandler, failedHandler){
$http.get(url)
.then(successHandler, failedHandler)
.then(null, function(resp){
if(resp.handled !== true){
//your awesome popup message triggers here.
}
})
}
}
3. Solution
Same as #2 but less code needed to achieve the same:
myhttp.get('url/to/the/endpoint', successCallback, failedCallback);
function successCallback(){ ... }
function failedCallback(resp){
//if you provide a failedCallback, and you still want to have your popup, then you need your reject.
$q.reject(resp);
}
Other example:
//since you didn't provide failed callback, it'll treat as a non-handled promise, and you'll have your popup.
myhttp.get('url/to/the/endpoint', successCallback);
function successCallback(){ ... }
The myhttp service implementation:
function myhttp($http){
var service = this;
service.get = get;
function get(url, successHandler, failedHandler){
$http.get(url)
.then(successHandler, failedHandler)
.then(null, function(){
//your awesome popup message triggers here.
})
}
}

Categories

Resources