Angular $cookies "Circular dependency found" - angularjs

got this error "Error: [$injector:cdep] Circular dependency found: $cookies <- $cookies <- AuthService"
with following code
'use strict';
angular.
module('core.auth').
factory('AuthService', [ '$http', '$rootScope', 'ConfigService', '$cookies',
function AuthService($http, $rootScope, ConfigService, $cookies) {
const service = {};
service.Login = Login;
service.SetCredentials = SetCredentials;
service.ClearCredentials = ClearCredentials;
return service;
function Login(username, password, callback) {
$http.post(ConfigService.LOGIN_API, { username: username, password: password })
.success(function (response) {
callback(response);
});
}
function SetCredentials(username) {
$rootScope.globals = {
currentUser: {
username: username
}
};
$cookies.put('globals', $rootScope.globals);
}
function ClearCredentials() {
$rootScope.globals = {};
$cookies.remove('globals');
}
}
]);
and i'm use this service in login component
'use strict';
angular.
module('login').
component('login', {
templateUrl: 'dist/components/login/login.template.html',
controller: ['$location', 'AuthService', '$log',
function LoginController($location, AuthService, $log) {
(function initController() {
// reset login status
AuthService.ClearCredentials();
}());
this.login = () => {
AuthService.Login(this.username, this.password, (response) => {
if (response.success) {
$log.log(response);
$log.log('Login successful', true);
AuthService.SetCredentials(this.username);
$location.path('#!/products');
} else {
$log.log(response)
}
})
}
}
],
controllerAs: 'vm'
});
can't understand whats wrong with my code... If remove $cookies from here, it's working perfectly. Maybe solution is write own cookies service? :)

A circular dependency is always the sign of mixing of concerns, which is a really bad thing.One of the authors of AngularJS, explains a nice solution on his awesome blog. In short, you probably have a third service hidden somewhere, which is the only part of your code really needed by the two others.

Related

How to use angular services with controllers

I'm new to angular and I've been told that it's better to make services do the heavy lifting for the controllers, but I'm finding it diffcult to make use of the services I've created. I've seen several questions on this but I can't find solutions.
Here's my service
(function () {
'use strict';
var office = angular.module('Office', []);
office.factory('auth', ['$http', '$localForage', '$scope', function ($http, $localForage, $scope) {
var auth = {}
auth.login = function (credentials) {
$http.post('/auth_api/login', credentials)
.then(function (data) {
$localForage.setItem('user', data.data)
},
function () {
$scope.login_error = 'Invalid Username/password'
})
}
$localForage.getItem('user').then(function (data) {
auth.isAuthenticated = !!data.id
})
return auth
}])
And here's my controller
office.controller('LoginController', ['$scope', 'auth', function ($scope, auth) {
$scope.login = auth.login($scope.user)
}])
I have created a simpler version from your code.. and its working here . check the link - fiddle
app.factory('auth', ['$http', function ($http) {
var auth = {};
auth.login = function (credentials) {
return "success";
}
return auth;
}]);
replace login function with your implemenation
Your code is correct but as you are not returning anything from the "auth" factory, you are not getting any update in the controller. Change your code as shown below to return the data from factory or any message acknowledging the login.
Factory :
(function () {
'use strict';
var office = angular.module('Office', []);
office.factory('auth', ['$http', '$localForage', '$scope', function ($http, $localForage, $scope) {
var auth = {}
auth.login = function (credentials) {
return $http.post('/auth_api/login', credentials)
.then(function (data) {
$localForage.setItem('user', data.data);
setAuthentication(true);
return data.data;
},
function (err) {
return err;
});
}
auth.setAuthentication = function (isLoggedIn){
this.isAuthenticated = isLoggedIn;
}
return auth;
}]);
Controller :
office.controller('LoginController', ['$scope', 'auth', function ($scope, auth) {
$scope.login = function (){
auth.login($scope.user).then(function (data){
$scope.userDetails = data;
}, function (err){
$scope.loginError = 'Invalid Username/password';
});
}
}]);

Angularjs Factoryname.function is not a function

I am trying to call a factory function from the controller .
My code:
angular.module("mainApp", ['ui.router', 'ngAnimate', 'toaster'])
.factory("authenticationSvc", function($http, $q, $window) {
var userInfo;
function login(userName, password) {
var deferred = $q.defer();
$http.post("/api/login", {
userName: userName,
password: password
}).then(function(result) {
userInfo = {
accessToken: result.data.access_token,
userName: result.data.userName
};
$window.sessionStorage["userInfo"] = JSON.stringify(userInfo);
deferred.resolve(userInfo);
}, function(error) {
deferred.reject(error);
});
return deferred.promise;
}
return {
login: login
};
})
.controller("LoginController", function($scope, toaster, $rootScope, $stateParams, $location, $http, authenticationSvc) {
$scope.login = authenticationSvc.login();
});
But I am getting an error
TypeError: authenticationSvc.login is not a function
The function login needs two parameter
So the function login without a parameter isn't definded
Firstly, the approach and formalization of factory is not done properly.
try using the following approach..
.factory("authenticationSvc", function($http, $q, $window) {
var userInfo;
var authenticationSvc={};
//Define login()
authenticationSvc.login=function(userName, password) {
var deferred = $q.defer();
$http.post("/api/login", {
userName: userName,
password: password
}).then(function(result) {
userInfo = {
accessToken: result.data.access_token,
userName: result.data.userName
};
$window.sessionStorage["userInfo"] = JSON.stringify(userInfo);
deferred.resolve(userInfo);
}, function(error) {
deferred.reject(error);
});
return deferred.promise;
}
//return Factory Object
return authenticationSvc;
})
And in the controller , try calling in the same approach
.controller("LoginController", function($scope, toaster, $rootScope, $stateParams, $location, $http, authenticationSvc) {
$scope.login = authenticationSvc.login();
});
Hope this helps.
Cheers
Here below is the basic example that how factories are behaving. Please change your code with below one
angular.module("mainApp", ['ui.router', 'ngAnimate', 'toaster'])
.factory("authenticationSvc", function($http, $q, $window) {
var userInfo, authentication = {};
authentication.login = function(userName, password) {
var deferred = $q.defer();
$http.post("/api/login", {
userName: userName,
password: password
}).then(function(result) {
userInfo = {
accessToken: result.data.access_token,
userName: result.data.userName
};
$window.sessionStorage["userInfo"] = JSON.stringify(userInfo);
deferred.resolve(userInfo);
}, function(error) {
deferred.reject(error);
});
return deferred.promise;
}
return authentication;
})
.controller("LoginController", function($scope, toaster, $rootScope, $stateParams, $location, $http, authenticationSvc) {
$scope.login = authenticationSvc.login(user,password);
});
Please check though I didn't test it. Inside in your factory :
You just create an object, add properties to it, then return that same
object. When you pass this service into your controller, those
properties on the object will now be available in that controller
through your factory.

Can't access service in controller

So I'm trying to retrieve a token from the server but I'm encountering an error when trying to call a method in my service.
LoginController.js:
(function(){
angular.module('app')
.controller('LoginController', [
'$http', 'authService',
LoginController
]);
function LoginController(authService ) {
var vm = this;
vm.user = {};
vm.login = function () {
console.log("logging in");
authService.getToken("admin", "admin")
.then(function (data) {
console.log(data);
}, function (error) {
//TODO: error handling
})
};
}
})();
authService.js:
(function(){
'use strict';
angular
.module('app')
.factory('authService', ['$http', '$rootScope', 'REST_END_POINT',
authService
]);
function authService($http, $rootScope, REST_END_POINT){
return {
getToken: function(username, password) {
var config = {
headers: {
'Accept': 'application/json'
}
};
var data = {
username: login,
password: password
};
return $http.post(REST_END_POINT, +"/authenticate", data, config);
}
};
}
})();
I keep getting this error :
TypeError: authService.getToken is not a function
at LoginController.vm.login
You forgot to add $http to your controller function.
angular.module('app')
.controller('LoginController', [
'$http', 'authService',
LoginController
]);
function LoginController(_$http_needs_to_be_here, authService ) {
...
Remove $http from this line since you have it injected in your service already
angular.module('app')
.controller('LoginController', [
'authService',
LoginController
]);
You have wrong no of params in LoginController function. You have request angular to inject $http and authService. But you have only one param in function. For more info pls read Angular DI
Re-write code:
(function(){
angular.module('app')
.controller('LoginController', [
'$http', 'authService',
LoginController
]);
function LoginController($http, authService ) {
var vm = this;
vm.user = {};
vm.login = function () {
console.log("logging in");
authService.getToken("admin", "admin")
.then(function (data) {
console.log(data);
}, function (error) {
//TODO: error handling
})
};
}
})();

Pass authentication error from factory to controller in AngularJS

I am trying to implement Firebase authentication via a factory and I would like to pass the error and even the authData object back to the controller from the factory. Is this possible? I can't seem to figure out how. I keep getting undefined variables.
If I print the error upon a failed login to console.log I get what should be expected, so the rest of this code works. I just can't pass the error/obj back to the controller.
My controller:
myApp.controller('LoginController', ['$scope', '$location', 'Authentication', function($scope, $location, Authentication) {
$scope.login = function() {
Authentication.login($scope.user);
// do something with error from auth factory
}
}]);
My factory:
myApp.factory('Authentication', ['$firebase', 'FIREBASE_URL', '$location', function($firebase, FIREBASE_URL, $location){
var ref = new Firebase(FIREBASE_URL);
var authObj = {
login: function(user) {
return ref.authWithPassword({
email : user.email,
password : user.password
}, function(error, authData) {
if (error) {
// pass error back to controller
// i've tried the following:
// authObj.err = error;
// return authObj.err = error;
}
else {
// pass authData back to controller
}
});
} // login
};
return authObj;
}]);
You simply pass an error handler function to the factory from the controller. Something like this (untested):
//Controller
myApp.controller('LoginController', ['$scope', '$location', 'Authentication', function($scope, $location, Authentication) {
$scope.login = function() {
Authentication.login($scope.user, function(error, authData) {
// access to error
});
}
}]);
//Factory
myApp.factory('Authentication', ['$firebase', 'FIREBASE_URL', '$location', function($firebase, FIREBASE_URL, $location){
var ref = new Firebase(FIREBASE_URL);
var authObj = {
login: function(user, errorHandler) {
return ref.authWithPassword({
email : user.email,
password : user.password
}, errorHandler);
} // login
};
return authObj;
}]);
Maybe you can do this in your controller:
$scope.login = function() {
Authentication.login(username, password).then(
function(result) {
$location.path('/stuff');
},
function(result) {
$scope.showLoginErrorMessage = true;
});
};
Note that then() takes 2 functions as parameters (one for success and one for error). This does depend on how your Authentication service works, but it looks OK to me.

Angularjs service doesn't work in run() method

I got a simple get and set service in my angular app, that stores data from a $http request, but for some reason it just doesn't seem to work in angular's run() method. I'm not sure what am doing wrong.
my service
app.factory('sessionService', function() {
var user_info = {};
return {
set: function(value) {
user_info = value;
},
get: function() {
return user_info;
}
};
});
my run method
app.run(['$rootScope', '$location', 'Auth', 'sessionService',
function($rootScope, $location, Auth, sessionService) {
var routespermission = ['/dashboard', '/create']; //route that require login
$rootScope.$on('$routeChangeStart', function() {
if (routespermission.indexOf($location.path()) != -1) {
Auth.check({
type: 'checkSession'
}).success(function(data) {
if (data.status === false) {
$location.path('/user/login');
} else {
sessionService.set(data);
}
});
}
});
}
]);
trying to access the data in my controller
app.controller('dashboardCtrl', ['$scope', '$location', 'sessionService',
function($scope, $location, sessionService) {
$scope.user_info = sessionService.get();
console.log($scope.user_info);
$scope.create_review = function() {
}
}
]);
when I console log the service in my controller, it return an empty object. I don't getany error, so not sure where i went wrong
you should inject $route dependency in app.run for '$routeChangeStart' to work.
app.run(['$rootScope', '$location','$route', 'Auth', 'sessionService',
function($rootScope, $location,$route, Auth, sessionService) {
var routespermission = ['/dashboard', '/create']; //route that require login
$rootScope.$on('$routeChangeStart', function() {
if (routespermission.indexOf($location.path()) != -1) {
Auth.check({
type: 'checkSession'
}).success(function(data) {
if (data.status === false) {
$location.path('/user/login');
} else {
sessionService.set(data);
}
});
}
});
}
]);

Resources