How to get response from service on controller - javascript

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`...
});

Related

How to get error from http service

I am trying to get http error if service failed to load a url. I have created a angular factory which is like this:
loadUsers: function () {
return $http.get(urlService.url("/users"));
},
in controller i try to using this factory method to load ruserlist:
urlservice.loadUsers()
.then(function(response) {
$log.info("user loaded");
})
.finally(data.bind(undefined, result));
at this point i want to handle http error but not getting idea where i have to use error function as this is returning a promise. Can someone give me hint.
Just add a .catch to your promise:
urlservice.loadUsers()
.then(function(response) {
$log.info("user loaded");
})
.catch(function(err) {
console.log(err);
})
.finally(data.bind(undefined, result));
add a second callback to the .thenmethod, that will be triggered in case of error.
from the angular doc:
https://docs.angularjs.org/api/ng/service/$http
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Just add another function inside promise like this
urlservice.loadUsers()
.then(function(response) {
$log.info("user loaded");
},function(response) {
$log.info("error");
})
.finally(data.bind(undefined, result));
urlservice.loadUsers().then(successCallback, errorCallback)
.finally(data.bind(undefined, result));
var successCallback = function(response) {
// handle data recieved
$log.info("user loaded");
};
// create generic method for handling service errors
var errorCallback = function(error) {
// handle error here
$log.info("error occurred");
};

Angular httpPromise

I have a request function :
function search(request) {
return $http.post('/path/to/resource', request);
}
I can call it like this :
search({/*...*/})
.success(function() {})
.error(function() {})
As I often need to find some objects by their ID, I need a shortcut function. I cannot find how to create this function so that I can also chain it with success() and error() functions.
I searched how to create a promise in angular and found the documentation about $q and this is what I tried :
function searchById(id) {
var deferred = $q.defer();
search({id: id}).
then(function (response) {
deferred.resolve(response.data.results[0]);
}, function (error) {
deferred.reject(error);
});
return deferred.promise;
}
I can only call it like this :
searchById().then(successCallback, errorCallback);
I would like to be able to call it like this :
searchById()
.success(successCallback)
.error(errorCallback);
The documentation about $q indicates that it returns a promise whereas the documentation about $http indicates that it returns an httpPromise but I cannot figure how to create an httpPromise.
Any idea?
In angular promises the error callback should be catch not error, try this
searchById()
.then(successCallback)
.catch(errorCallback);
sjokkogutten is correct that you don't need to use $q in this case you can simplify this
var deferred = $q.defer();
search({id: id}).
then(function (response) {
deferred.resolve(response.data.results[0]);
}, function (error) {
deferred.reject(error);
});
return deferred.promise;
to this
return search({id: id}).
then(function (response) {
return response.data.results[0];
}
$http is already returning a promise, so there is no need to use $q.defer(). Also, success() and error() has been depreciated (since 1.4.4), you should use then() instead.
Call your function like this:
search(request).then(function(data){
// successcallback
}, function(error){
// errorcallback
})
Creating a factory with $http functions will allow you to use .success and .error. But you really should be using .then.
app.factory("dataService", function($http) {
return {
search: function() {
return $http.get('path/to/api');
},
searchById: function(payload) {
return $http.post('path/to/api', payload);
},
searchMoreThings: function(payload) {
if(payload === "foo") payload = "bar";
return $http.post('path/to/api', payload);
}
}
});
You can do:
dataService.searchById(searchTerm).success().error();
Here is an actual example :
app.controller('controller',function($scope,$rootScope,$http,){
$scope.login = function(request){
var promise = $http.post(/path/to/resource, request, {
headers: {
'Content-Type': 'application/json'
}
}).then(function success(res){
//it worked, you have data in res
},function error(res){
// it failed
});
};
});

Angular ui-router not injecting the resolve into controller

I'm just getting started with Angular and Express and facing tough times with it. I come from a java background and want to learn Angular and Express and therefore trying out to build one small application.
What I'm trying to do: I have given a password reset link to user so as to change his password. The link is something like:
localhost:9000/reset/:token
Now, I have created a simple view which shows an input box to change his password if token is valid otherwise prints an error if token is invalid based on ng-show property of angular.
Problem: Before I can render my above created view, I want ui-router to check if the :token is valid or not. I will be using the information of validity of token in my controller to control ng-show property mentioned above.
After reading this I tried to leverage the $stateProvider.state functionality with a resolve so as to get the response of validation of token as pre-requisite. This will help me when rendering the actual view where I'm using ng-show technique to show error message or input box to change the password based on the ui-router resolve promiseObject.
What is the issue now ?
Well, after breaking my head for too long, I decided to post my question over here. Can anyone please help me here ?
My questions:
1. I'm able to get the data/err from the api call but somehow ui-router is not injecting it in my controller. Can anyone tell me am I doing anything wrong here ?
2. Right now if the token is not valid, I'm returning a 404 in response from my backend api. But the factory method in frontend takes it as err (Is this expected in Node.js ?) and the err is thrown which results in deferred.reject(). Now, if I go with ui-router definition, if the promise is not resolved then the view won't be rendered, right ? Is there any way by which I can pass this err also to my controller ? Reason why I'm asking to pass err is, my view's ng-show logic is based on the response code (4xx/2xx) depending on which I'll show error message or input box.
Code snippets:
Factory Method which calls the rest api:
isPasswordResetTokenValid: function(token, callback) {
var cb = callback || angular.noop;
var deferred = $q.defer();
return User.getUserByPasswordResetToken(token,
function(data) {
deferred.resolve(data);
return cb(data);
},
function(err) {
deferred.reject(err);
return cb(err);
}.bind(this)).$promise;
}
'use strict';
angular.module('scrubApp')
.config(function ($stateProvider) {
$stateProvider
.state('passwordreset', {
url: '/reset/:token',
templateUrl: 'app/account/passwordreset/passwordreset.html',
resolve: {
promiseObj2: function($stateParams, Auth){
var token = $stateParams.token;
console.log(token);
var response = Auth.isPasswordResetTokenValid({token: token})
.then( function(response) {
console.log(response); // shows response
if(response.status == 404) {
//$scope.token-expiry = true;
return response;
}
if(response.status == 200) {
// $scope.user = response.data;
}
})
.catch( function(err) {
console.log(err); // shows error
return err;
});
}
},
controller: 'ResetPasswordCtrl'
});
});
ResetPasswordCtrl controller:
'use strict';
angular.module('myApp')
.controller('ResetPasswordCtrl', function ($scope, User, Auth, Mailer, $stateParams, promiseObj2) {
$scope.errors = {};
$scope.user = {};
console.log(promiseObj2); // This is coming undefined
$scope.isTokenExpired = promiseObj2; // Not able to inject promiseObj2
$scope.isFormSubmitted = false;
});
Thanks in advance
Your resolve promiseObj2 should return a promise from promise service, so that your controller will wait till promise gets resolved.
return Auth.isPasswordResetTokenValid({token: token})
Update
If you want to handle some logic on failure of your token request then you could handle it in your promise itself, that can do couple of thing like
You could redirected to other page using $state.go('login') or $state.go('error') page.
Code
promiseObj2: function($stateParams, Auth, $state){
var token = $stateParams.token;
console.log(token);
return Auth.isPasswordResetTokenValid({token: token}) //added return here
.then( function(response) {
console.log(response); // shows response
if(response.status == 404) {
$state.go('error')
}
if(response.status == 200) {
return response;
}
})
.catch( function(err) {
console.log(err); // shows error
return err;
});
}
If you want to show html page anyhow if error occurs then You could also return data from the .then of promiseObj2 object that will have information about error message. So that error information is return to the controller
Code
promiseObj2: function($stateParams, Auth, $state){
var token = $stateParams.token;
console.log(token);
return Auth.isPasswordResetTokenValid({token: token}) //added return here
.then( function(response) {
console.log(response); // shows response
if(response.status == 404) {
return {status: 404, data: "doen't found resource"}
}
if(response.status == 200) {
return response;
}
})
.catch( function(err) {
console.log(err); // shows error
return err;
});
}
Then inside controller we will get resolve the promise of promiseObj2 object and then you will get the value of error in the .then function of it.
angular.module('myApp')
.controller('ResetPasswordCtrl', function ($scope, User, Auth, Mailer, $stateParams, promiseObj2) {
$scope.errors = {};
$scope.user = {};
promiseObj2.then(function(resp){
console.log(resp)
$scope.isTokenExpired = resp.isTokenExpired;
}, function(err){
console.log(err)
})
});
Update
If we want to handle a condition where server return 4XX status that means our ajax will call catch function that won't return promise though. We could solve this case by creating custom promise using $q and we will resolve it from the promiseObj2
Code
promiseObj2: function($stateParams, Auth, $state, $q){
var token = $stateParams.token,
deffered = $q.defer();
console.log(token);
Auth.isPasswordResetTokenValid({token: token}) //added return here
.then( function(response) {
console.log(response); // shows response
if(response.status == 404) {
//return {status: 404, data: "doen't found resource"}
deffered.resolve({status: 404, data: "doen't found resource"});
}
if(response.status == 200) {
//return response;
deffered.resolve(response);
}
})
.catch( function(err) {
console.log(err); // shows error
deffered.resolve(err);
});
return deffered.promise;
}

Not able to retrieve the response from the angular js service

I wrote a angular js service which returns the response. But when I tried to call the service from the controller I am not able to get the exact response.
app.service('testservice', function($http){
var details= {};
details.getResponse = function() {
return $http({
url: 'send/getdata',
method: 'GET'
}).success(function(data, status, headers, config) {
this.getdata = data;
return getdata;
});
};
return details;
});
I am using the below controller to call the method.
app.controller('testcontroller',[ '$scope', '$http','testService',function($scope, $http,testService) {
var targetresponse = testService.getResponse();
alert(JSON.stringify(targetresponse))
})]);
I am getting the below response,
{"$$state":{"status":0,"pending":[[{"promise":{"$$state":{"status":0}}},null,null,null]]}}
Kindly, let me know the error here.
Your testservice service getResponse method should return a promise, and you can continue that promise chain inside your controller.
Service
details.getResponse = function() {
return $http({
url: 'send/getdata',
method: 'GET'
}).then(function(res) {
this.getdata = res.data;
return res.data;
});
};
You can use resolve that promise and get access of data inside .then function
var targetresponse = testService.getResponse();
targetresponse.then(function(data){
alert(JSON.stringify(data))
})
Srv.getData().then(function (success) {
var data = success.data;
$scope.myData = data;
}, function (error) {
});
Best way to to this.

AngularJS callback, copy the behavior of $http. Turn cache into promise

I want to create a cache for my http requests, so I want to duplicate the $http callbacks.
this is my function:
function getData() {
if(cacheExists()) {
return cache;
}
return $http({
method: 'POST',
url: 'http://something.com',
params: {something}
});
}
and this is how I handle it:
getData()
.success(function(data) {
$scope.spot = data.data;
console.log($scope.spot);
}).error(function(data) {
console.log('error');
});
this will work perfectly with angularjs $http method,
but will not work with my "cache", becuase the "cache" should have those callbacks: success & error, how do I create them?
Its because the $http returns a promise. You can solve this by using the $q service and return the cache as a promise.
//inject $q
function getData() {
var deffered = $q.defer()
if(cacheExists()) {
deffered.resolve(cache);
} else {
$http({
method: 'POST',
url: 'http://something.com',
params: {something}
})
.success(function(data) {
deffered.resolve(data);
})
.error(function(response) {
deffered.reject(response);
})
}
return deffered.promise;
}
So what's happening here that you are creating "deffered" as a promise. A Promise is basically a way to handle async tasks. And when you get a promise you need to resolve it, as you did with your return value from the http call. But with a $q deffered you are using 'then' instead of 'success'. Consider the code snippet below:
getData()
.then(function(data) {
$scope.spot = data.data;
console.log($scope.spot);
})
Hope this helps.
UPDATE
As of you example by handling errors you could do this:
getData()
.then(function(data) {
if(data.data) {
$scope.spot = data.data;
console.log($scope.spot);
} else {
console.log("its an err");
}
});
Or this
getData()
.then(successCallback, errorCallback);
function successCallback(data) {
$scope.spot = data.data;
console.log($scope.spot);
}
function errorCallback() {
console.log("its an err");
}

Categories

Resources