Search code examples
angularjsangularjs-directiveangularjs-service

How to bind service value with directive scope so that view updates when model changes?


I'm using an isAuthenticated value in my service. For some reason, it won't update the view when the service model changes.

app.factory('AuthService', function($timeout) {
    var isAuthenticated = false;

    $timeout(function () {
        isAuthenticated = true; }, 2000);

    return {
       data: {'isLoggedIn': isAuthenticated}
    }
});

app.directive('appMainMenu', function (AuthService) {
    return {
        restrict: 'A',
        link: function (scope) {
            scope.model = AuthService;
        }
    };
});

Then the HTML:

<div app-main-menu>
    <a href="#login" ng-show="!model.data.isLoggedIn">Guest can Login</a>
    <a href="#logout" ng-show="model.data.isLoggedIn">Member can Logout</a>
</div>

Any idea why this doesn't work?

Before I was using a function but that does recursive loop (stops after 10th time) on every $digest, so I don't think that's the right way to do it. It's a method someone on here suggested to me a while back.

It looks like:

app.factory('AuthService', function($timeout) {
    var isAuthenticated = false;

    $timeout(function () {
        isAuthenticated = true; }, 2000);

    return {
        isLoggedIn: function () {
            return isAuthenticated;
        }
    }
});

app.directive('appMainMenu', function (AuthService) {
    return {
        restrict: 'A',
        link: function (scope) {
            scope.isLoggedIn = function () {
                return AuthService.isLoggedIn();
            };
        }
    };
});

<div app-main-menu>
    <a href="#login" ng-show="!isLoggedIn()">Guest can Login</a>
    <a href="#logout" ng-show="isLoggedIn()">Member can Logout</a>
</div>

The end result is that works, but if you console.log(...) inside isLoggedIn() you'll see that it's firing 10 times on every $digest.


Solution

  • It's not updated in the view because your service doesn't update it. :)

    When your service is created by the factory function, the return value (which would become your service Object) is:

    { data: {'isLoggedIn': isAuthenticated} }
    

    with isAuthenticated being the value that it was at the time you returned the object. It's equivalent to:

    { data: {'isLoggedIn': false} }
    

    This is because isAuthenticated is a Boolean - a primitive value, that is assigned "by-value", not "by-reference".

    If you did something like the following, it would work:

    app.factory('AuthService', function($timeout) {
        var isAuthenticated = false;
        var svc = {data: {isLoggedIn: isAuthenticated }};
        $timeout(function () {
            svc.data.isAuthenticated = true; }, 2000);
    
        return svc;
    });