AngularJS - How to Expose Service Properties
I'm having a hard time exposing the properties of an Angular service. In the example below, I am exposing two properties in authService
: isAuthenticated
and user
. However, when isAuthenticated
it does change, it doesn't get picked up HomeController
. Can anyone help me understand where I am wrong?
(function() {
'use strict';
// Define the 'app' module
angular.module('app', []);
// Use the 'app' module
angular
.module('app')
.controller('LoginController', LoginController)
.controller('HomeController', HomeController)
.factory('authService', authService);
// ----- LoginController -----
LoginController.$inject = ['authService'];
function LoginController(authService) {
var vm = this;
vm.username = null;
vm.password = null;
vm.login = login;
function login() {
authService.login(vm.username, vm.password);
}
}
// ----- HomeController -----
HomeController.$inject = ['$scope', 'authService'];
function HomeController($scope, authService) {
var vm = this;
vm.user = null;
$scope.$watch(
function() { return authService.isAuthenticated; },
function() {
console.log('HomeController: isAuthenticated changed');
vm.user = authService.user;
}
);
}
// ----- authService -----
function authService() {
var isAuthenticated = false;
var user = { username: 'jdoe', location: 'Dreamland' };
var service = {
login: login,
isAuthenticated: isAuthenticated,
user: user
};
return service;
function login(username, password) {
user = {
username: username,
location: 'Boston'
};
isAuthenticated = true;
console.log('authService: isAuthenticated changed');
}
}
})();
Here is the index.html file:
<!DOCTYPE html>
<html data-ng-app="app" ng-strict-di>
<head>
<meta charset="utf-8">
<title>AngularJS Minimal Template</title>
<link rel="stylesheet" href="app.css">
</head>
<body>
<div ng-controller="LoginController as vm">
<form name="loginForm" ng-submit="vm.login()">
<label>Username: </label>
<input type="text" name="username" ng-model="vm.username">
<label>Password: </label>
<input type="password" name="password" ng-model="vm.password">
<button type="submit">Login</button>
</form>
</div>
<div ng-controller="HomeController as vm">
<h1>{{vm.user.username}}</h1>
<h2>{{vm.user.location}}</h2>
</div>
<!-- JavaScript at the bottom for fast page loading -->
<script src="lib/angular.js"></script>
<script src="app.js"></script>
</body>
</html>
source to share
When you do this:
var service = {
login: login,
isAuthenticated: isAuthenticated,
user: user
};
You are making copies login
, isAuthenticated
and user
(although it user
is a reference to the same object).
Then when you do this:
function login(username, password) {
user = {
username: username,
location: 'Boston'
};
isAuthenticated = true;
console.log('authService: isAuthenticated changed');
}
You are reassigning the local variable user
to the new object and the local variable isAuthenticated
to true
. Your object service
is still referring to the old values โโof these variables.
The easiest way to fix this is to assign directly to your service variables:
function login(username, password) {
service.user = {
username: username,
location: 'Boston'
};
service.isAuthenticated = true;
console.log('authService: isAuthenticated changed');
}
This way the service variables will be updated and should be reflected wherever the service is used. In this case, you no longer need local variables - the service object already hosts them. Use local variables for private, unexposed variables.
source to share
Instead of this
var service = {
login: login,
isAuthenticated: isAuthenticated,
user: user
};
Try to do this
var service = {
login: login,
isAuthenticated: function() { return isAuthenticated; },
user: function() { return user; }
};
Then you need to call it as a function not as a value. This will check for the value isAuthenticated
and return it every time you call service.isAuthenticated()
. You must do the same with user
. You have to call service.user()
.
source to share