Controller not logging response from Nodejs using Angular $http service - javascript

I created a form and onclick of the form i want to see the response from the server(nosejs). In Angular Controller Im calling the service. The response is visible when called from the service itself, but when called from the controller nothing shows up.
Controller:
MyApp.angular.controller("loginCtrl", function($scope, UserService){
$scope.name = "TestName";
$scope.check = function(user){
UserService.createUser(user, function(response){
$scope.userinfo = response;
console.log("FROM Ctrlr: " + response);
});
}
});
Service:
MyApp.angular.factory("UserService", function($http,$location){
var service = {
createUser: createUser
};
return service;
function createUser(user){
$http.post("/register", user).then(function(response){
console.log("FROM Srvc:" +response);
});
}
});
NodeJS:
app.post("/register", function(req, res){
var user = req.body;
res.json(user);
});
I can see the response logged to the console if I call it from the Service. But no response when called from the controller itself. Reason to include MyApp.angular.factory and MyApp.angular.controller is I have declared MyApp in another config file.
What am I doing wrong?

In order to get the response in your controller from the factory change your createUser func in your factory like this:
function createUser(user){
//notice the return here!!!
return $http.post("/register", user).then(function(response){
console.log("FROM Srvc:" +response);
return response.data; //notice the return here too!!!
});
}
You need to return the promise inside the function and inside the then return the result as well in order to get access to it from wherever you call the function.

Unlike node.js which uses callback-based APIs, the AngularJS framework uses promise-based APIs. Return the promise and use its .then method:
Controller
app.controller("loginCtrl", function($scope, UserService){
$scope.name = "TestName";
$scope.check = function(user){
//UserService.createUser(user, function(response){
//USE .then method
return UserService.createUser(user).then(function(data) {
$scope.userinfo = data;
console.log("FROM Ctrlr: " + data);
return data;
}).catch(function(errorResponse) {
console.log(errorResponse.status);
throw errorResponse;
});
}
});
Service
function createUser(user){
var promise = $http.post("/register", user).then(function(response){
var data = response.data;
console.log("FROM Srvc:" +data);
//RETURN data to chain
return data;
});
//RETURN promise
return promise;
}
Don't convert promise-based APIs to callback-type APIs. It's considered an anti-pattern.
See Why are Callbacks from Promise .then Methods an Anti-Pattern.

You need to add 1 more parameter, callback and return the response to the callback function
function createUser(user, callback){
$http.post("/register", user).then(function(response){
console.log("FROM Srvc:" +response);
callback(response); // return the response in the callback function
});
}

Related

Using a value from a get with ngResource in the controller

I'm struggling with using the value that I got from a 'get' in my controller.
This is my code in my controller
vm.user;
function onInit(){
loadUser(vm.queryParams.id[0]);
console.log(vm.user);
}
function loadUser(UserId) {
var defer = $q.defer();
User.get({ id: userId }).$promise.then(function (user) {
vm.user = user;
defer.resolve();
});
return defer.promise;
};
When I print the vm.user in the onInit() it is undefined. While when I look on the view where vm.user is called it just shows me the correct values of the user. So it's not known after the loadUser() in the controller but it is in my view.
I would like to first 'get' the user and then use it for further logic in the onInit(). How to retrieve the user properly so I can further use it and call its values in the onInit()?
You have to wait till the execution of loadUser() is finished so as the get the value of user.You can use the promise returned like this and do any calcualtions on it.
vm.user;
function onInit(){
var promise=loadUser(vm.queryParams.id[0]);
promise.then(function(response){
console.log(response);
});
}
function loadUser(UserId) {
var defer = $q.defer();
User.get({ id: userId }).$promise.then(function (user) {
vm.user = user;
defer.resolve(vm.user);
});
return defer.promise;
};
Immediately invoke your init function at the beginning of your controller and convert your loadUser function to a service since its a get action. Your service will return the user which you can then set.
(Declare at top of controller):
init();
function init(){
loadUserService.loadUser(UserId)
.then(function (user) {
vm.user = user;
defer.resolve();
})
}

How do you handle errors from chained promises?

I am building an Angular app, and have a factory that executes an XHR, and returns the promise to the controller that called it. When I get an error, it gets caught in the factory fail method but because I'm returning it as a promise, it still calls the success method in the controller. Is there a way that I can get the factory error to pass on to the controller fail method and prevent the controller success method from being called? Reason being is that I'd like to properly display success and error notifications on the client side. Am I just going about this entirely wrong?
Example factory method:
function add(payload) {
return $http.post('/companies', payload)
.then(success)
.catch(fail);
function success(response) {
return response.data;
}
function fail(error) {
$log.log('Company Factory XHR failed: ', error.data);
}
}
Corresponding controller method:
function add(isValid) {
if (isValid) {
var payload = {
company: vm.new_company
};
companyFactory.add(payload)
.then(success)
.catch(fail);
}
function success() {
getCompanies();
vm.new_company = {};
toastrFactory.success("Added company!");
}
function fail(err) {
$log.log('Companies Controller XHR Failed: ' + err.data);
}
}
You don't need to handle the promise in the factory if you are handling it in the controller.
In the factory you want to just
return $http.post('/companies', payload);
Then handle it like you are already in your controller and you're good to go.
Using .then and .catch are functions on a promise, the way you are doing it now in your factory, you aren't returning a promise, you are returning other things after the promise is resolved. You just want to return the promise alone, which is the $http.post() function.
Edit:
To add a little more depth, this is how I setup my factories for this kind of stuff...
function factory() {
var self = {};
self.addCompany = function(payload) {
return $http.post('/companies', payload);
}
return self;
}
Then handle it in controllers like
factory.addCompany(payload)
.then(function(data) {
console.log('success', data);
})
.catch(function(data) {
console.log('something happened', data);
})

How to get response from service on controller

I'm trying to separate the $http.post() call into a ".factory()", But would like to fetch the response which is coming async on the controller. Is there a way of doing that?
Controller:
Login.post($scope.user);
Factory:
.factory( 'Login' , function($http,SERVERURL){
var serverUrl = SERVERURL;
return {
'post' : function(user){
$http.post(serverUrl+'/login', user).
then(function(response) {
console.log(response);
}, function(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
}
};
})
There is a .then() but I want that on the controller, so I can behave accordingly. Thank you!
Basically you need to return the $http.post promise, and from success function you could return a data that will return to the consumer of this method. So that you could easily call the factory method from controller & inside .then function of that call you could have success and error function.
Code
.factory('Login', function($http, SERVERURL) {
var serverUrl = SERVERURL;
return {
'post': function(user) {
return $http.post(serverUrl + '/login', user).
then(function(response) {
console.log(response);
return response.data; //return data from here
}, function(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
}
};
})
Controller
Login.post().then(function(data){ //success function
console.log(data)
}, function(error){ //error function
console.log(error);
})
You could add a callback param.
.factory( 'Login' , function($http,SERVERURL){
var serverUrl = SERVERURL;
return {
'post' : function(user, callback){
$http.post(serverUrl+'/login', user).
then(function(response) {
console.log(response);
callback(null, response);
}, function(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
callback(response);
});
}
};
})
And your controller will become:
Login.post($scope.user, function(err, response) {
if(err) {} //do something if there is an error
// or deal with the response
});
To return any response to controller just do:
return {
'post' : function(user){
return $http.post(serverUrl+'/login', user);
}
};
In your controller you will already call.then()
Angular's $http methods return a Promise.
The $http API is based on the deferred/promise APIs exposed by the $q service.
Factory
Your method post is not yet returning anything but can quite simply return the Promise which is created by calling $http.post:
.factory('Login' , function($http, SERVERURL){
var serverUrl = SERVERURL;
return {
'post' : function (user) {
return $http.post(serverUrl + '/login', user)
// ^^^^^^
.then(function (response) {
console.log(response);
return response.data;
}, function (response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
}
};
});
Controller
Then consume the result of the returned Promise by calling then on it:
Login.post($scope.user).then(function (res) {
// do something with `res`...
});

Angularjs get object values outside of function

I need to get localeData value print out side of below function.
I know how to print in side of function like what i did here.
I have tried this but didn't work.
$http.post(SERVER_URL + 'getLocaleData').success(function(localeData) {
console.log(localeData);
}).error(function(err) {
alert('warning', err.message);
});
//need to get that value here.
console.log(localeData);
EDIT
Actually i need to do is this
app.factory('customLoader', function($http, $q, SERVER_URL) {
return function(options) {
var deferred = $q.defer();
// do something with $http, $q and key to load localization files
$http.post(SERVER_URL + 'getLocaleData').success(function(localeData) {
//do something here to localData
}).error(function(err) {
alert('warning', err.message);
});
deferred.resolve(localeData);
return deferred.promise;
};
});
This is what i need. finally i need to send localeData.
You don't need to create & resolve a defer yourself. There is an easier way. (Also in the example you give, you resolve promise before the underlying ajax completed)
Angular.js $http service follows $q interface too! So you can write:
app.factory('customLoader', function($http, $q, SERVER_URL) {
return function(options) {
var promise = $http.post(SERVER_URL + 'getLocaleData')
.then(function(localeDataBag) {
var localeData = localeDataBag.data; // .data of 'then' equals to what .success returns.
modifiedLocaleData = localeData++; // do something here to localData
return modifiedLocaleData; // This is the new result
})
.catch(function(err) {
console.log(err);
return $q.reject(err); // This is the new result if something failed. Since we are chaining promises, we should keep failure state.
});
return promise;
};
});
You don't need $q to accomplish your objective:
app.factory('customLoader', ["$http", "SERVER_URL", function($http, SERVER_URL) {
return function(options) {
return $http.post(SERVER_URL + 'getLocaleData');
};
}]);
Because $http and all it's convenience methods actually return a promise. In this case, you can use this service as follows:
customLoader(options).success(function(localeData){
//do something here to localData
}).error(function(err){
alert('warning', err.message);
});
If you really must use $q, then this should do:
app.factory('customLoader', ["$http", "$q", "SERVER_URL", function($http, $q, SERVER_URL) {
return function(options) {
return $q(function(resolve, reject){
$http.post(SERVER_URL + 'getLocaleData').success(function(localeData) {
//do something here to localData
resolve(localeData); // ultimately you ought to resolve inside this function
}).error(function(err) {
alert('warning', err.message);
reject(localeData); // ultimately you ought to reject inside this function
});
});
};
}]);
JS is asynchronous, which basically means that your last console.log will be executed before your server returned any data. So you have to do it inside both your promises:
$http.post(SERVER_URL + 'getLocaleData').success(function(localeData) {
console.log(localeData);
}).error(function(err) {
console.log(err);
alert('warning', err.message); //Just in case you didn't know, this line supposes that your server returns a JSON object with a "message"-property
});
That way, your server-response will be console.log'ed both on success and failure.
Reference
Edit: If you really wanna do it the other way:
var response; //First, declare a variable in the parent scope.
$http.post(SERVER_URL + 'getLocaleData').success(function(localeData) {
response = localeData; //Assign the response data to the variable.
console.log(localeData);
}).error(function(err) {
alert('warning', err.message); //Just in case you didn't know, this line supposes that your server returns a JSON object with a "message"-property
});
console.log(response);
The example won't evaluate as you expect, though. The last console.log will just log undefined.
By following way you can access your server response outside factory in the controller:
app.factory('customLoader', function ($http, $q) {
return {
response: {},
getLocalData: function (param) {
var deferred = $q.defer();
$http.post(SERVER_URL + 'getLocaleData', param).
success(function (data, status, headers, config) {
deferred.resolve(data);
}).
error(function (data, status, headers, config) {
});
return deferred.promise;
}
}
});
app.controller('yourCtrl', function($scope,customLoader) {
$scope.GetLocaleData= function() {
customLoader.getLocalData({
Role: role,
Email_Id: $scope.Email,
Pwd: $scope.Password
}).then(function(localeData) {
$scope.Data = localeData;
});
}
});
localeData is limited to the scope of .success function. You cant get it outside unless you assign it some other variable.
var data = ""
$http.post(SERVER_URL + 'getLocaleData').success(function(localeData) {
data = localeData;
}).error(function(err) {
alert('warning', err.message);
});
//need to get that value here.
console.log(data);
But dont expect to get the desired value in data until you get the response back. $http.post is async
Take a look at promises to overcome such issues, because they are used all over the place, in angular world.
UPDATE:
As you have done in the edit, you may either use $q service like:
app.factory('customLoader', function($http, $q, SERVER_URL) {
return function(options) {
var deferred = $q.defer();
// do something with $http, $q and key to load localization files
$http.post(SERVER_URL + 'getLocaleData').success(function(localeData) {
//do something here to localData
}).error(function(err) {
alert('warning', err.message);
});
deferred.resolve(localeData);
return deferred.promise;
};
});
OR, you may simply return $http.post which itself returns a promise
app.factory('customLoader', function($http, $q, SERVER_URL) {
return function(options) {
return $http.post(SERVER_URL + 'getLocaleData');
};
});
In either way, you are returning a promise object and not just the actual response you get from server. The localeData can be accessed as follows:
customLoader().success(function(res){
console.log(res);
}).error(function(){
//show some error message
})

Asynchronus calls in angularjs

I am new to Javascript and Angularjs. I wanted to know , how to call a function asynchronously without waiting for it to return from it.
Please let me know and if there is some example then it would be very helpful.
Regards,
nG
Use Angular's deferred:
function myAsyncFunction() {
var deferred = $q.defer();
//..
setTimeout(function() {
deferred.resolve({ message: "resolved!" });
// or deferred.reject({ message: "something went terribly wrong!!" });
}, 1000);
//..
return deferred.promise;
}
myAsyncFunction()
.then(function(data){
// success
console.log("success", data.message);
}, function(data) {
// fail
console.log("error", data.message);
}).finally(function() {
// always
});
You can use a deferred to return a promise, you can then resolve the promise once your function is complete. Try something like this:
http://jsfiddle.net/adcoxwga/
var myApp = angular.module('myApp',[])
.service('myService', function($q, $timeout){
this.someFunction = function(){
var deferred = $q.defer(); //making a new deferred
$timeout(function(){
deferred.resolve('something'); //resolving the deferred with a response
}, 3000);
return deferred.promise; //returning a promise
}
})
.controller('MyCtrl', function($scope, myService){
myService.someFunction().then(function(response){ //calling the asynchronous function
console.log(response); //getting response
}, function(error){
console.log(error); //getting error
});
});
You have a couple of different options ahead of you, but one thing to note is that you have to use a callback or promise for asynchronous activity. Since you are using angular, I'd suggest using promise's.
Using a promise
If you are writing an http call to an api, you can use either $http or $resource. If you start to research angular providers, you will see that $http returns a promise, while $resource returns a promise but you must call it specifically to access it. For instance:
someService
function someServiceFunction () {
return $http.get('some/url');
}
someController
$scope.results = [];
someService.someServiceFunction().then(function(data) {
$scope.results = data;
});
Something to note is that the first returned function is the success scenario and if you declare a second callback, then it is the failure scenario.
If you were to use callbacks in the same scenario:
Using a callback
someService
function someServiceFunction (callback) {
return $http.get('some/url')
.success(callback);
}
someController
$scope.results = [];
someService.someServiceFunction(function(data, status, headers, config) {
$scope.results = data;
});
Here's a link to the $http provider.
Here's a link to the $resource provider.
Cheers!

Categories

Resources