Reputation: 25793
I am having a hard time exposing properties from an Angular service. In the example below, I am exposing two properties in authService
: isAuthenticated
and user
. However when isAuthenticated
changes, it is not picked up by the HomeController
. Can someone help me understand where I am going 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's 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>
Upvotes: 4
Views: 3702
Reputation: 4121
Instead of doing this
var service = {
login: login,
isAuthenticated: isAuthenticated,
user: user
};
Try doing 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. That will check isAuthenticated
value and return it everytime you call service.isAuthenticated()
. You should do the same with user
. You should call service.user()
.
Upvotes: 0
Reputation: 1917
When you do this:
var service = {
login: login,
isAuthenticated: isAuthenticated,
user: user
};
You're creating copies of login
, isAuthenticated
, and user
(although 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 user
variable to a new object and the local isAuthenticated
variable to true
. Your service
object still refers to the old values of these variables.
The most straight forward 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 anywhere that the service is used. In this scenario, you don't need the local variables anymore - the service object already houses them. Use local variables for private, unexposed variables.
Upvotes: 5