How to inject ngCookies into provider() - javascript

I have been trying, without success, to inject the Angular JS ngCookie module and $cookies service into an Angular Provider. Can someone please explain the lac of success?
When I inject ngCookies into the Provider
angular.module('loginService', [])
.provider('loginService', function () {
var userToken = localStorage.getItem('userToken'),
errorState = 'app.error',
logoutState = 'app.home';
this.$get = function ($rootScope, $http, $q, $state) {
/**
* Low-level, private functions.
*/
var setHeaders = function (token) {
if (!token) {
delete $http.defaults.headers.common['X-Token'];
return;
}
$http.defaults.headers.common['X-Token'] = token.toString();
};
...
});
like so:
angular.module('loginService', ['ngCookies'])
.provider('loginService', ['$cookies', function ($cookies) {
var userToken = localStorage.getItem('userToken'),
errorState = 'app.error',
logoutState = 'app.home';
I get an error:
Unknown provider: $cookies
I suspect that I can't inject Services into Providers? My issue is that I am calling a web service which is returning a session id as a Set-Cookie header. I'd like to grab the ss-id but can't seem to retrieve it from the response header so thought I'd get it from the cookie instead.
I'm open to better alternatives though...

You can only inject other providers into a provider. It is only possible to inject a service in the public functions or config block of the provider.

Related

Circular dependency found in angular js

Tring to add interceptor header for my every request, however, it is giving me below error.
Uncaught Error: [$injector:cdep] Circular dependency found: $http <- Auth <- httpRequestInterceptor <- $http <- $templateRequest <- $route
app.js
var app= angular.module('myDemoApp',['ngRoute'])
app.factory('httpRequestInterceptor', ['Auth', function (Auth) {
return {
request: function (config) {
config.headers['x-access-token'] = Auth.getToken();
return config;
}
};
}]);
app.config(function ($httpProvider) {
$httpProvider.interceptors.push('httpRequestInterceptor');
});
Auth Service
(function () {
'use strict';
myDemoApp.factory('Auth', ['$http', '$window', Auth]);
/******Auth function start*****/
function Auth($http, $window) {
var authFactory = {};
authFactory.setToken = setToken;
authFactory.getToken = getToken;
return authFactory;
/*setToken function start*/
function setToken(token) {
if (token) {
$window.localStorage.setItem('token', token);
} else {
$window.localStorage.removeItem('token');
}
}
/*getToken function start*/
function getToken() {
return $window.localStorage.getItem('token')
}
}
})();
You can't do this because.
You have created httpRequestInterceptor which intercepts all $http requests.
Now, you are passing Auth in the httpRequestInterceptor.
If you'll see, Auth uses $http request inside itself.
So, your interceptor can itself cause a http request using Auth.
Hence, its circular error and angularjs wont allow you to do that !
Remove $http from Auth factory OR dont insert a service into interceptor which itself uses $http.
I hope you got, how the infinite loop chain being created, hence a circular dependency error !

How to make factory data available before controller loads page in angularJS

I am making an $http call using factory and sharing the data to all controllers.
Actually I am getting that data from config.json file, but first on load data is not getting broadcasted to all controllers.
I want data to be available before controller can make further calls inside.
My config.json has app_key, app_secret, base_url etc, here is my factory (JS code)
JS
.factory('UserService', function($http, $rootScope) {
$http.get('config.json').success(function(data) {
var app_key = data.app_key;
var app_secret = data.app_secret;
var base_url=data.base_url;
window.localStorage['app_key'] = app_key;
window.localStorage['app_secret'] = app_secret;
window.localStorage['base_url'] = base_url;
})
return {
app_key : window.localStorage['app_key'],
app_secret : window.localStorage['app_secret'],
base_url:window.localStorage['base_url'],
}
})
my config.json file looks like this
{
"app_key" : "my_app_key_here",
"app_secret" : "my_app_secret_here",
"base_url" : "http://base_url.com",
}
The reason I am returning app_key: window.localStorage['app_key'] is just because I need to access this service data like userService.app_key in controller.
ngoApp.controller('loginCtrl',['$scope','$http', '$localStorage', '$state','UserService','$rootScope', function($scope, $http, $localStorage, $state, UserService, $rootScope) {
//I want to access app_key as below format
$scope.app_key=UserService.app_key;
}]);
Can anyone please tell me what mistake I am making?
The right place where to load this dependencies is in your module run/config method.
Check documentation here: https://docs.angularjs.org/guide/module#module-loading-dependencies for example and more information...

How to get data from an API in a Angular Service and store it to be used by anyone in the future

This is more of a writing clean code/ optimizing existing code.
I am writing my Angular Services to fetch data from backend like this
angular.module('myApp').service('Auth', ['$http', '$q', 'Config', function($http, $q, Config) {
this.getUser = function() {
return $http.get(Config.apiurl + '/auth/user')
.then(function(response) {
return response.data;
}, function(error) {
return $q.reject(error.data);
});
};
}]);
Now in this, I am calling getUser function n number of times from the Database.
Now the question is, is it okay to call this service to get n times redundant data or I should it be saved somewhere say rootscope to be accessed later? Or storing in root scope would be bad practice and I should consider some other option or nothing at all?
Would like to get some views on Angular Community here.
Here is a sample example on how to use factory for sharing data across the application.
Lets create a factory which can be used in entire application across all controllers to store data and access them.
Advantages with factory is you can create objects in it and intialise them any where in the controllers or we can set the defult values by intialising them in the factory itself.
Factory
app.factory('SharedData',['$http','$rootScope',function($http,$rootScope){
var SharedData = {}; // create factory object...
SharedData.appName ='My App';
return SharedData;
}]);
Service
app.service('Auth', ['$http', '$q', 'SharedData', function($http, $q,SharedData) {
this.getUser = function() {
return $http.get('user.json')
.then(function(response) {
this.user = response.data;
SharedData.userData = this.user; // inject in the service and create a object in factory ob ject to store user data..
return response.data;
}, function(error) {
return $q.reject(error.data);
});
};
}]);
Controller
var app = angular.module("app", []);
app.controller("testController", ["$scope",'SharedData','Auth',
function($scope,SharedData,Auth) {
$scope.user ={};
// do a service call via service and check the shared data which is factory object ...
var user = Auth.getUser().then(function(res){
console.log(SharedData);
$scope.user = SharedData.userData;// assigning to scope.
});
}]);
In HTML
<body ng-app='app'>
<div class="media-list" ng-controller="testController">
<pre> {{user | json}}</pre>
</div>
</body>
Instead of rootScope just use a local variable of user in your service that can be accessed from anywhere in your code and so you doesn't have to call the api every time.
angular.module('metaiotAdmin').service('Auth', ['$http', '$q', 'Config', function($http, $q, Config) {
this.getUser = function() {
if(this.user){
return this.user;
}
else{
return $http.get(Config.apiurl + '/auth/user')
.then(function(response) {
this.user = response.data;
return response.data;
}, function(error) {
return $q.reject(error.data);
});
}
};
}]);
Hope it helps.
You don't have to, $http already caches your request for you, if the same request is applied in case you set the cache config option to true.
$http.get('/hello', { cache: true})
.then(onResponse)
or you can either set it for every request, by using either an interceptor or override the http instance in the $httpProvider, to apply the effect for every http request.
app.module('app.module')
factory('MyHttpInterceptor', function() {
return {
request : function(config) {
config.cache = true;
return config;
},
// rest of implementation of the interceptor
}
});
app.module('app.module')
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('MyHttpInterceptor');
// ... rest of the configuration
}]);
Or :
app.module('app.module')
.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.cache = true;
// ...
}]);
see :
Angular doc for caching

How use inside common provider $http in Angular 1.4?

I try to use common provider and in angular app config function set data in provider.
.provider('userData', function() {
var authUser = {};
return {
checkUser: function() {
// wish to able use $http here for request to get data from service
// save all data into 'authUser' object
// $get return 'authUser' object
},
getCookie: function(value) {
// wish to able use $http here
},
$get: function() {
// only for return object
return authUser;
}
}
})
app.config(['userDataProvider', function(userDataProvider) {
userDataProvider.checkUser();
});
.controller('headerCtrl', ['$scope', 'userData', '$http', function($scope, userData, $http) {
// use inside all controllers/directives 'userData'
});
I try to use $http as parameter in $get function -> not working: error:
$get: function($http) {
return authUser;
}
Also I can't find any valid example for using $http inside provider. Inside service/factory $http work fine, but I need to prepare data in provider from config function.
Services, factory & value aren't available at config phase by design.
You could do it in run()
app.run(['userData', function(userData) {
userData.checkUser();
});

Angular dependency injection does not recognise module

I'm having trouble properly injecting a bunch of modules in a project. This is the project I’m following
https://thinkster.io/django-angularjs-tutorial
When i try to make a new post - angular throws the below error
Error: Authentication.getAuthenticatedAccount(...) is undefined
submit#http://localhost:8000/static/javascripts/posts/controllers/new-post.controller.js:31:21
$parseFunctionCall#http://localhost:8000/static/bower_components/angular/angular.js:12474:15
This is where the problem seems to occur
function NewPostController($rootScope, $scope, Authentication, Snackbar, Posts) {
var vm = this;
vm.submit = submit;
function submit() {
$rootScope.$broadcast('post.created', {
content: vm.content,
author: {
username: Authentication.getAuthenticatedAccount().username
}
});
$scope.closeThisDialog();
Posts.create(vm.content).then(createPostSuccessFn, createPostErrorFn);
function createPostSuccessFn(data, status, headers, config) {
Snackbar.show('Success! Post created.');
}
function createPostErrorFn(data, status, headers, config) {
$rootScope.$broadcast('post.created.error');
Snackbar.error(data.error);
}
}
}
But I can see that the correct module is being used in the code.
this is my new-post.controller.js file where i've injected the Authentication dependency
angular
.module('thinkster.posts.controllers')
.controller('NewPostController', NewPostController);
NewPostController.$inject = ['$rootScope', '$scope', 'Authentication', 'Snackbar', 'Posts'];
this is a snippet my posts.module.js file
angular
.module('thinkster.posts', [
'thinkster.posts.controllers',
'thinkster.posts.directives',
'thinkster.posts.services'
]);
angular
.module('thinkster.posts.controllers', []);
this is a snippet of the authentication service module
angular
.module('thinkster.authentication.services')
.factory('Authentication',Authentication);
Authentication.$inject = ['$cookies','$http'];
function Authentication($cookies,$http){
var Authentication = {
getAuthenticatedAccount: getAuthenticatedAccount,
isAuthenticated: isAuthenticated,
register:register,
login : login,
logout:logout,
setAuthenticatedAccount: setAuthenticatedAccount,
unAuthenticate: unAuthenticate
};
return Authentication;
function getAuthenticatedAccount(){
if (!$cookies.authenticatedAccount){
return;
}
return JSON.parse($cookies.authenticatedAccount);
}
And a snippet of the authentication module
angular
.module('thinkster.authentication',[
'thinkster.authentication.controllers',
'thinkster.authentication.services'
]);
-finally, the below thinkster module
angular
.module('thinkster', [
'thinkster.config',
'thinkster.routes',
'thinkster.authentication',
'thinkster.layout',
'thinkster.posts',
'thinkster.utils'
]);
the authentication service works fine since I’m able to login and logout of the project. Am i looking in the wrong place for the error?
The code snippets are missing the NewPostController definition. Without seeing that code, I would guess that the Authentication object may not be passed into the function.
function NewPostController($rootScope, $scope, Authentication, Snackbar, Posts) {
}
You can see what methods are available on your Authentication object with the following code in NewPostController:
for (var key in Authentication) {
console.log(typeof Authentication[key], key);
}
You should see "function getAuthenticatedAccount" if it's available on the object.

Categories