AngularJS : Service variable changes not applying

Im currently having an issue where when I call a function in a service that changes its own internal variable it doesn't appear to stay unless I change it from a controller. When I output the variable to the console right after I change it, it appears with the correct value. However when I call a function in the controller that prints the object to console it shows the original value.

The variable Im having issues with is "isSignedIn" which always shows false (confirmed with the $scope.verify method in login controller) even after the line "console.log('Signin:' + isSignedIn);" shows true.

Thanks ahead of time for any guidance!

Service Skype

angular.module('Skype', ['ng'])
    .service('skypeClient', function () {
        //Service Properties
        var client = new Skype.Web.Model.Application;
        this.errors = [];
        this.errorCount = -1;
        var isSignedIn = false;
        var state = 'SignedOut';

        var init = function () { 
            client.signInManager.state.when('SignedIn', function () {
                isSignedIn = true;
                console.log('Signin:' + isSignedIn); // This outputs the correct value
            });
            property = client.signInManager.state;
            property.changed(function (status) { 
            state = status;
           console.log("New State"+status) });
           }

        //Signin Function
        var signIn = function (username,password) {
            client.signInManager.signIn({
                username: username,
                password: password
            }).then(function () {
               isSignedIn = true;
                this.errorCount++;
                console.log(this.errorCount);
            });
        }

        //SignOut Function
        var signOut = function () {
        client.signInManager.signOut()
        .then(function () {
           this.isSignedIn = false;
        }, function (error) {
            this.erros.push(error);
            this.errorCount++;
        });
        }

        return {
            signIn: signIn,
            signOut: signOut,
            init: init,
            state: state,
            isSignedIn: isSignedIn
        };

});

Controller Login

'use strict';
angular.module('login', ['ngRoute', 'classy', 'Metio.Skype'])
.config(['$routeProvider', function ($routeProvider) {
    $routeProvider.when('/login', {
        templateUrl: 'app/views/login.html',
        controller: 'loginCntrl'
    });
}]).controller('loginCntrl', function ($scope,skypeClient) {

    skypeClient.init();

    $scope.skypeClient = skypeClient;
    console.log('LoginCntrl Loaded');

    $scope.signIn = function () {
        skypeClient.signIn($scope.user, $scope.password);
    }
    $scope.signOut = function () {
        skypeClient.signOut();
    }
    $scope.verify = function () {
        console.log(skypeClient);
    }
});

[EDIT] Modified Code according to pdenes recommendations(comments), same issue but cleaner

Factory Skype

.factory('skypeClient', function () {
        //Service Properties
        var client = new Skype.Web.Model.Application;
        var state = 'SignedOut';
        //Initialize Listeners
        var init = function () {
            client.signInManager.state.when('SignedIn', function () {
                console.log('Signin:' + state); // This outputs the correct value
            });
            property = client.signInManager.state;
            property.changed(function (status) {
                state = status;
                console.log("New State" + state);
            });
            console.log('init');
           }
        //Signin Function
        var signIn = function (username, password) {
           client.signInManager.signIn({
                username: username,
                password: password
            }).then(function () {console.log('LoggedIn');});
        }
        init();
        return {
            signIn: signIn,
            state: function(){return state}
        }
   });

Controller Login

.controller('loginCntrl', function ($scope,skypeClient) {
    $scope.skypeClient = skypeClient;
    $scope.signIn = function () {
        skypeClient.signIn($scope.user, $scope.password);
    }
    $scope.verify = function () {
        console.log(skypeClient);
        console.log($scope.skypeClient);
    }
});

DOM Markup

<input type="checkbox">Keep Me Signed In (Currently Signedin: {{skypeClient.state()}} )

Console Output and DOM Changes

When I hit the signin function the console logs "New State SigningIn" and the dom changes to "Currently Signedin: SigningIn" but when I get the next event fired the console logs "New State SignedIn" but the DOM still reflects the old value "Currently Signedin: SigningIn" so the binding only appears to update the first time but not subsequent times.


The value in the object that you return as the service is not the same as the isSignedIn variable you defined earlier. So:

...
var isSignedIn = false;
...
return {
   isSignedIn: isSignedIn  
   //          ^this is false when the object is created
   //           and will remain false, no matter how you
   //           change the value of the above variable later
};

To expose the value of isSignedIn in your closure from the service, you'd need a function, something like:

...
return {
  ...
  isSignedIn: function () { 
    return isSignedIn; // <- this refers to the above variable itself 
  }
};

EDIT: Follow up for the updated code in the question...

So apparently the value is updated properly internally, but the {{skypeClient.state()}} binding is still not updated (only when some other action somehow "forces" it). This is probably happening because the value is updated by something outside of Angular's digest cycle, so there is nothing telling Angular to update things at the right moment.

Looking at the code, state is assigned a new value inside a callback for property.changed (btw, property should properly be declared with var !). Try wrapping that line in an $apply() to make Angular update the bindings!


In place where you call service (factory) value that is returned by function add a $watch. That will update value if it changes in the service.

$scope.$watch(function() { return ModalService.getInfo(); }, function(){
    $scope.info = ModalService.getInfo();
}); 

See solution

链接地址: http://www.djcxy.com/p/77540.html

上一篇: 在控制器中更改$ scope变量值不会更改视图上的值

下一篇: AngularJS:服务变量更改不适用