AngularJS get value from service function - angularjs

I have a problem with getting value from service in my controller.
I get the value from API using service:
angular.module('app').factory('service',
['$q', '$rootScope', '$timeout', '$http',
function ($q, $rootScope, $timeout, $http) {
// create user variable
var user = null;
// return available functions for use in the controllers
return ({
isLoggedIn: isLoggedIn,
getUserStatus: getUserStatus,
login: login,
getEmail: getEmail
});
function isLoggedIn() {
if(user) {
return true;
} else {
return false;
}
}
function getUserStatus() {
return $http.get('/user/status')
// handle success
.success(function (data) {
if(data.status){
user = true;
} else {
user = false;
}
})
// handle error
.error(function (data) {
user = false;
});
}
function login(username, password) {
// create a new instance of deferred
var deferred = $q.defer();
// send a post request to the server
$http.post('/user/login',
{username: username, password: password})
// handle success
.success(function (data, status) {
if(status === 200 && data.status){
user = true;
deferred.resolve();
} else {
user = false;
deferred.reject();
}
})
// handle error
.error(function (data) {
user = false;
deferred.reject();
});
// return promise object
return deferred.promise;
}
function getEmail() {
// create a new instance of deferred
var deferred = $q.defer();
$http.get('/email/'+$rootScope.username)
.success(function (data) {
console.log(data);
deferred.resolve();
})
.error(function (data) {
deferred.reject();
})
return deferred.promise;
}
}]);
and I'm trying to get and use value in the controller:
angular.module('app')
.controller('myController', ['$rootScope', '$scope', '$state', '$http', '$q', 'service', function ($rootScope, $scope, $state, $http, $q, service) {
$scope.email;
$scope.getEmail = function() {
// call getEmailFromDB from service
service.getEmail()
// handle success
.then(function (data) {
$scope.email = data; //here I got undefined
console.log($scope.email);
})
// handle error
.catch(function () {
$scope.error = true;
$scope.errorMessage = "wrong#mail.com";
});
};
$scope.getEmail();
}]);
but in the controller there is undefined value.
In my console:
Regarding the documentation of $q, I use then() function in service and controller.
Does anybody know where is the problem?

you forgot to send your result in your service like this
deferred.resolve(data);

In your code you are not returning anything with the promise, to do that you must call deferred.resolve(data) or deferred.reject(data).
Instead of creating a deferred object, you can simply return the $http request.
Example:
function getEmail() {
return $http.get('/email/'+$rootScope.username).then(
function success(data){
console.log(data);
return data;
},
function error(data){
console.error(data);
}
);
}
Also notice that .success() and .error() are deprecated, you should use .then() and pass the success and error functions.

Related

undefined service response in controller to store in variable using angular?

I have a factory, calling the service and getting the response and passing in to the controller and trying to store the response in a variable which is getting undefined
app.factory('Myservice', function (service1, service2) {
return {
getService: function (data) {
service1("user", encodeURIComponent("pass")).then(function (response) {
varSessionData = response.Obj;
var queryString = strURL[1].split("&");
Service2.pageLoad(SessionData).then(function (response) {
var homeScreen = response;
data(homeScreen);
});
});
}
};
});
In Controller:
var Mydata = MyService.geService(function (data) {
Console.log(data);
return data; // getting response
});
$scope.Hello = Mydata; // undefined
Whenever you make any AJAX request they are asynchronous. That is why Angular promises are used (the .then method). So you should change your code like this in your controller:
MyService.geService(function (data) {
Console.log(data);
$scope.Hello = data;
});
Change it to the following, your data isn't defined synchronously.
Controller:
MyService.geService(function(data) {
$scope.Hello = data;
});
i have pass the $scope.Hello in Another Service controller,which means depend upon that taking the result from services.
Not working?
var HomeController = function ($scope, $rootScope, $http, $stateParams, $state, Service3, Myservice)
{
MyService.geService(function (data) {
Console.log(data);
$scope.Hello = data;
});
Not working
Service3.pageLoad($scope.Hello) // not get the value
.then(function (response) {
$scope.ServiceModelobj = response;
console.log(response);
}
Working code
var HomeController = function ($scope, $rootScope, $http, $stateParams, $state, Service3, Myservice)
{
MyService.geService(function (data) {
Console.log(data);
$scope.Hello = data;
Working//
Service3.pageLoad($scope.Hello) // get the value
.then(function (response) {
$scope.ServiceModelobj = response;
console.log(response);
});
}
}

Promise returning object in angular js

i have my authservice as given below ,
myApp.factory('Authentication',
['$rootScope', '$location', 'URL', '$http', '$q',
function ($rootScope, $location, URL, $http, $q) {
var myObject = {
authwithpwd: function (user) {
var dfd = $q.defer();
$http
.post('Mart2/users/login', {email: user.email, password: user.password})
.then(function (res) {
return dfd.resolve(res.data);
}, function (err) {
return dfd.reject(err.data);
});
return dfd.promise;
} //login
};
return myObject;
}]); //factory
And i'm using that service in user service as follows :
myApp.factory('UserService',
['$rootScope', '$location', 'URL', '$http', '$q', 'Authentication',
function ($rootScope, $location, URL, $http, $q, $Authentication) {
var myObject = {
login: function (user) {
$Authentication.authwithpwd(user).then(function (regUser) {
console.log(regUser);
}).catch(function (error) {
$rootScope.message = error.message;
});
},
getUserToken: function () {
return $rootScope.currentUser.apiKey;
},
isLogged: function () {
if ($rootScope.currentUser) {
return true;
} else {
return false;
}
}
//login
};
return myObject;
}]); //factory
I am very new to angular js . While writing service and calling that service from controller i have put a console debug in user service which is showing its returning object .i am getting object if i do console.log(regUser) ? any idea why ?
To get the object you need to do change your myObject declaration. Basically you need to return a promise from the login function and then write a callback to get the resolved data.
myApp.factory('UserService',
['$rootScope', '$location', 'URL','$http','$q','Authentication',
function($rootScope,$location, URL,$http,$q,$Authentication) {
var myObject = {
login: function(user) {
var defer = $q.defer();
$Authentication.authwithpwd(user).then(function(regUser) {
console.log(regUser);
defer.resolve(regUser);
}).catch(function(error) {
$rootScope.message = error.message;
defer.reject(regUser);
});
return defer.promise;
},
getUserToken:function() {
return $rootScope.currentUser.apiKey;
},
isLogged:function() {
if($rootScope.currentUser){
return true;
} else {
return false;
}
}//login
};
return myObject;
}]); //factory
To extract the object from controller or from some other service you need to write a callback
UserService.login(user)
.then(function (data) {
$scope.data = data;
}, function (error) {
$scope.error = error;
});
Also in the Authentication service you can just do a 'dfd.resolve' instead of 'return dfd.resolve'; since you are already returning the dfd.promise.
I have created a fiddler here

Pass URL path into $http get url- AngularJS

I'm trying to get a value from a URL part, into my $http getURL request. I have tried a few solutions (such as HTML5mode) but have not had success.
Here is my code:
angular.module('myapp123.products', [])
.factory('productsApi', ['$http', '$location',
function($http, $location){
var BASE_URL = 'http://stashdapp-t51va1o0.cloudapp.net/api/item/';
return {
get: getApiData
};
function getData() {
var product_id = $location.path().split("/")[3] || "Unknown"; //URL = /#/product/id/1234 <---
return $http.get(BASE_URL + product_id);
}
}]
)
.controller('productsCtrl', ['$scope', '$log', 'productsApi', 'UserService',
function($scope, $log, productsApi, UserService) {
$scope.isVisible = function(name){
return true;// return false to hide this artist's albums
};
// <====== Rewrite with accounts preferences
productsApi.getApiData()
.then(function (result) {
//console.log(JSON.stringify(result.data)) //Shows log of API incoming
$scope.products = result.data;
})
.catch(function (err) {
$log.error(err);
});
}
]);
The code in your example has a lot of syntax errors in it. Here is what it should look like, based on what I think you are going for...
angular.module('myapp123.products', [])
.config(locationConfig)
.factory('productsApi', productsApiFactory)
;
locationConfig.$inject = ['$locationProvider'];
function locationConfig($locationProvider) {
$locationProvider.html5Mode(true);
}
productsApiFactory.$inject = ['$http', '$location'];
function productsApiFactory($http, $location) {
var BASE_URL = 'http://stashdapp-t51va1o0.cloudapp.net/api/list/';
return {
get: getData
};
function getData() {
var product_id = $location.path().split("/")[3] || "Unknown";
return $http.get(BASE_URL + product_id);
}
}
In this version, the config function is correctly defined to set up html5mode and the service factory is configured to use $location each time the get() method is called.
You would use the service in a controller like this:
ExampleController.$inject = ['productsApi'];
function ExampleController(productsApi) {
productsApi.get()
.then(function onSuccess(res) {
// handle successful API call
})
.catch(function onError(err) {
// handle failed API call
})
;
}

How to make a $http request from the rest client in AngularJs?

Have this scenario when I make a request via $http in the first service, and then I want to manipulate the data in other service. For some reassons my returned object is empty. Any advice ?
.factory('widgetRestService',['$http','$log',function($http,$log){
var serviceInstance = {};
serviceInstance.getInfo = function(){
var request = $http({method: 'GET', url: '/rest/widgets/getListInfoDashboards'})
.then(function(success){
serviceInstance.widgets = success.data;
$log.debug('serviceInstance.widgets SUCCESS',serviceInstance.widgets);
},function(error){
$log.debug('Error ', error);
$log.debug('serviceInstance.widgets ERROR',serviceInstance.widgets);
});
return request;
};
serviceInstance.getAllWidgets = function () {
if (serviceInstance.widgets) {
return serviceInstance.widgets;
} else {
return [];
}
};
return serviceInstance;
}])
.factory('OtherService',['widgetRestService','$log', function(widgetRestService, $log){
widgetRestService.getInfo();
// and now I want to return widgetRestService.widgets [{things},{things},{things}]
return widgetRestService.getAllWidgets(); // returns []
}])
Result: [ ]
You must wait for your HTTP request to complete before trying to access the data that it returns. You can do this by accessing getAllWidgets within a then attached to the Promise returned by getInfo.
.factory('OtherService', ['widgetRestService','$log', function(widgetRestService, $log) {
return widgetRestService.getInfo().then(function () {
return widgetRestService.getAllWidgets();
});
}])
Consume OtherService somewhere:
OtherService.then(function (widgets) {
// do something with `widgets`...
});
It seems you have to return promise instead of response to get the data from another service.
serviceInstance.getInfo = function(){
var deferred = $q.defer();
$http({method: 'GET', url: '/rest/widgets/getListInfoDashboards'})
.then(function(success){
deferred.resolve(success.data);
},function(error){
$log.debug('Error ', error);
$log.debug('serviceInstance.widgets ERROR',serviceInstance.widgets);
});
return deferred.promise;
};
widgetRestService.getInfo() is returning a promise, so you have to wait for its resolution:
.factory("OtherService", ["widgetRestService", "$log", "$q"
function (widgetRestService, $log, $q) {
var deferred = $q.defer();
widgetRestService.getInfo().then(function () {
// only here, you're sure `serviceInstance.widgets` has been set (unless an error occurred when requesting the api)
deferred.resolve(widgetRestService.getAllWidgets());
});
return deferred.promise;
}])
Then, e.g. in a controller:
.controller("SomeController", ["$scope", "OtherService"
function ($scope, OtherService) {
OtherService.then(function (allWidgets) {
$scope.allWidgets = allWidgets;
});
}])

How to set a variable from an $http call then use it in the rest of the application WITHOUT making the whole application asynchronous

I have this data
{
"config": {
"RESTAPIURL": "http://myserver/myrestsite"
}
}
and I have this factory that reads that data
'use strict';
angular.module('myApp').factory('api',
["$http", "$q",
function ($http, $q) {
function _getConfiguration() {
var deferred = $q.defer();
$http.get('/scripts/constants/config.json')
.success(function (data) {
deferred.resolve(data);
})
.error(function (data, status) {
deferred.reject(data, status);
});
return deferred.promise;
}
function _restApiUrl() {
// this doesn't work either. _getConfiguration() doesn't resolve here.
return _getConfiguration().RESTAPIURL + '/api/';
}
return {
URL: _restApiUrl
}
}
]
);
Then to use it
'use strict';
angular.module('myApp').factory('AuthService', function ($http, $q, api,NotificationService) {
function _get(creds) {
var deferred = $q.defer();
$http({method: 'GET', url: api.URL() + api.AUTH, headers: {
'Authorization': 'Basic '+creds}
})
.success(function (data, status, results, headers) {
deferred.resolve(results);
})
.error(function (data, status) {
NotificationService.redirect(status);
deferred.reject(data, status);
});
return deferred.promise;
}
return {
get:_get
};
});
So when I'm using it I am doing api.URL() and it's not working.
It used to be hard coded URL so to call it used to be api.URL. I really don't want to go through the whole app and convert everything to api.URL().then(...). That would suck.
So how can I nail down this value as a "property" instead of an asynchronous promise that has to be called over and over?
Call it once, fine. Get the value. Put it somewhere. Use the value. Don't ever call the $http again after that.
EDIT
This is turning up to be one of the most successful questions I've ever asked, and I am gratefully going through each answer in turn. Thank each one of you.
Adding a bit to what #ThinkingMedia was saying in the comment, with ui-router when defining controllers you can add a resolve parameter.
In it you can specify some promises that have to resolve before the controller is instantiated, thus you are always sure that the config object is available to the controller or other services that the controller is using.
You can also have parent/child controllers in ui-router so you could have a RootController that resolves the config object and all other controllers inheriting from RootController
.state('root', {
abstract: true,
template: '<ui-view></ui-view>',
controller: 'RootController',
resolve:{
config: ['api', function(api){
return api.initialize();
}
}
});
and your api factory:
angular.module('myApp').factory('api',
["$http", "$q",
function ($http, $q) {
var _configObject = null;
function initialize() {
return $http.get('/scripts/constants/config.json')
.then(function (data) {
_configObject = data;
return data;
});
}
// you can call this in other services to get the config object. No need to initialize again
function getConfig() {
return _configObject;
}
return {
initialize: initialize,
getConfig: getConfig
}
}
]
);
I would pass a callback to the getURL method, and save the URL when it returns. Then I would attach any subsequent requests to that callback. Here I am assuming that you are doing something similar with api.AUTH that you don't have a reference to in your code.
Pass a callback to the getURL method in the api service.
angular.module('myApp').factory('api', ["$http", "$q",
function ($http, $q) {
function _getConfiguration() {
var deferred = $q.defer();
$http.get('/scripts/constants/config.json')
.success(function (data) {
deferred.resolve(data);
})
.error(function (data, status) {
deferred.reject(data, status);
});
return deferred.promise;
}
return {
getURL: function (cb) {
var that = this;
if (that.URL) {
return cb(that.URL);
}
_.getConfiguration().then(function (data) {
that.URL = data.config.RESTAPIURL + "/api";
cb(that.URL);
});
}
}
}]);
And in your AuthService, wrap your _get inside a callback like this:
angular.module('myApp').factory('AuthService', function ($http, $q, api, NotificationService) {
function _get(creds) {
var deferred = $q.defer();
var getCallback = function (url) {
$http({
method: 'GET',
url: url + api.AUTH,
headers: {
'Authorization': 'Basic ' + creds
}
})
.success(function (data, status, results, headers) {
deferred.resolve(results);
})
.error(function (data, status) {
NotificationService.redirect(status);
deferred.reject(data, status);
});
};
api.getURL(getCallback);
return deferred.promise;
}
return {
get: _get
};
});
Why don't you initialize the factory when the app is loading and put the variable onto another property? Something like this:
angular.module('myApp').factory('api', ["$http", "$q",
function ($http, $q) {
// store URL in a variable within the factory
var _URL;
function _initFactory() {
var deferred = $q.defer();
$http.get('/scripts/constants/config.json')
.success(function (data) {
// Set your variable after the data is received
_URL = data.RESTAPIURL;
deferred.resolve(data);
});
return deferred.promise;
}
function getURL() {
return _URL;
}
return {
initFactory: _initFactory,
URL: getURL
}
}
]
);
// While the app is initializing a main controller, or w/e you may do, run initFactory
//...
api.initFactory().then(
// may not need to do this if the URL isn't used during other initialization
)
//...
// then to use the variable later
function _get(creds) {
var deferred = $q.defer();
$http({method: 'GET', url: api.URL + api.AUTH, headers: {
'Authorization': 'Basic '+creds}
})
.success(function (data, status, results, headers) {
deferred.resolve(results);
})
return deferred.promise;
}
I see you haven't used any $resource's here, but I'm hoping you have a good understanding of them:
in factories/delay-resource.js:
'use strict'
angular.module('myApp').factory('delayResource', ['$resource', '$q',
function($resource, $q){
var _methods = ['query', 'get', 'delete', 'remove', 'save'];
var shallowClearAndCopy = function(src, dst) {
dst = dst || {};
angular.forEach(dst, function(value, key){
delete dst[key];
});
for (var key in src) {
if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
dst[key] = src[key];
}
}
return dst;
}
var delayResourceFactory = function(baseUrlPromise, url, paramDefaults){
var _baseUrlPromise = baseUrlPromise,
_url = url,
_paramDefaults = paramDefaults;
var DelayResource = function(value){
shallowClearAndCopy(value || {}, this);
};
_methods.forEach(function(method){
DelayResource[method] = function(params, successCB, errCB, progressCB){
if (angular.isFunction(params)) {
progressCB = successCB;
errCB = errHandlers;
successCB = params;
errHandlers = params = null;
}
else if (!params || angular.isFunction(params)){
progressCB = errCB;
errCB = successCB;
successCB = errHandlers;
params = {};
}
var _makeResultResource = function(url){
var promise = $resource(url, _paramDefaults)[method](params);
(promise.$promise || promise).then(
function successHandler(){
var data = arguments[0];
if (isInstance){
if (angular.isArray(data))
for (var i = 0; i < data.length; i++)
data[i] = new DelayResource(data[i])
else if (angular.isObject(data))
data = new DelayResource(data)
}
successCB.apply(successCB, arguments)
resultDelay.resolve.apply(resultDelay.resolve, arguments)
},
function(err){
errCB.apply(errCB, arguments)
resultDelay.reject.apply(resultDelay.reject, args)
},
function(){
progressCB.apply(progressCB, arguments)
resultDelay.notify.apply(resultDelay.notify, arguments)
}
)
}
var isInstance = this instanceof DelayResource,
resultDelay = $q.defer();
if (!angular.isString(_baseUrlPromise) && angular.isFunction(_baseUrlPromise.then))
_baseUrlPromise.then(
function successCb(apiObj){
_makeResultResource(apiObj.RESTAPIURL + _url)
},
function successCb(){
throw 'ERROR - ' + JSON.stringify(arguments, null, 4)
})
else
_makeResultResource(_baseUrlPromise.RESTAPIURL + _url);
return resultDelay.promise;
};
DelayResource.prototype['$' + method] = function(){
var value = DelayResource[method].apply(DelayResource[method], arguments);
return value.$promise || value;
}
});
return DelayResource;
}
return delayResourceFactory;
}]);
This will be the base factory that all requests to that REST API server will go through.
Then we need a factories/api-resource.js:
angular.module('myApp').factory('apiResource', ['delayResource', 'api', function (delayResource, api) {
return function (url, params) {
return delayResource(api.URL(), url, params);
};
}])
Now all factories created will just have to call the apiResource to get a handle on a resource that will communicate with the REST API
Then in a file like factories/account-factory.js
angular.module('myApp').factory('AuthRoute', ['apiResource', 'api', function (apiResource, api) {
return apiResource(api.AUTH);
}]);
Now in factories/auth-service.js:
'use strict';
angular.module('myApp').factory('AuthService', ['$q', 'AuthRoute', 'NotificationService', function ($q, AuthRoute, api, NotificationService) {
function _get(creds) {
var deferred = $q.defer();
AuthRoute.get()
.then(
function successCb(results){
deferred.resolve(results);
},
function errCb(){
// cant remember what comes into this function
// but handle your error appropriately here
//NotificationService.redirect(status);
//deferred.reject(data, status);
}
);
return deferred.promise;
}
return {
get:_get
};
}]);
As you can imagine, I haven't been able to test it yet, but this is the basis. I'm going to try create a scenario that will allow me to test this. In the mean time, feel free to ask questions or point out mistakes made
Late Addition
Forgot to add this:
'use strict';
angular.module('myApp').factory('api', ["$http", "$q", function ($http, $q) {
var restApiObj,
promise;
function _getConfiguration() {
if (restApiObj)
return restApiObj;
if (promise)
return promise;
promise = $http.get('/scripts/constants/config.json')
.then(function (data) {
restApiObj = data;
promise = null;
return data;
},
function (data, status) {
restApiObj = null;
promise = null;
});
return promise;
}
return {
URL: _getConfiguration
}
}]);
Continuing with the ui-router scenario
.state('member-list', {
url: '/members?limit=&skip='
templateUrl: '/views/members/list.html',
controller: 'MemberListCtrl',
resolve:{
members: ['$stateParams', 'MembersLoader', function($stateParams,MembersLoader){
return MembersLoader({skip: $stateParams.skip || 0, limit: $stateParams.limit || 10});
}
}
});
factory
.factory('MemberRoute', ['apiResource', function(apiResource){
return apiResource('/members/:id', { id: '#id' });
}])
.factory('MembersLoader', ['MembersRoute', function(MembersRoute){
return function(params){
return MemberRoute.query(params);
};
}])
.factory('MemberFollowRoute', ['apiResource', 'api', function(apiResource, api){
return apiResource(api.FOLLOW_MEMBER, { id: '#id' });
}])
controller
.controller('MemberListCtrl', ['$scope', 'members', 'MemberRoute', 'MemberFollowRoute', function($scope, members, MemberRoute, MemberFollowRoute){
$scope.members = members;
$scope.followMember = function(memberId){
MemberFollowRoute.save(
{ id: memberId },
function successCb(){
//Handle your success, possibly with notificationService
},
function errCb(){
// error, something happened that doesn't allow you to follow memberId
//handle this, possibly with notificationService
}
)
};
$scope.unfollowMember = function(memberId){
MemberFollowRoute.delete(
{ id: memberId },
function successCb(){
//Handle your success, possibly with notificationService
},
function errCb(){
// error, something happened that doesn't allow you to unfollow memberId
//handle this, possibly with notificationService
}
)
};
}]);
With all this code above, you will never need to do any sort of initialization on app start, or in some abstract root state. If you were to destroy your API config every 5 mins, there would be no need to manually re-initialize that object and hope that something isn't busy or in need of it while you fetch the config again.
Also, if you look at MembersRoute factory, the apiResource abstracts/obscures the api.URL() that you were hoping not to have to change everywhere. So now, you just provide the url that you want to make your request to, (eg: /members/:id or api.AUTH) and never have to worry about api.URL() again :)

Resources