简体   繁体   中英

AngularJS controller not updated by factory

I have two controllers and one factory. The first controller makes an http request to a server and gets back a string which it writes into the factory. Then the second controller should be updated with the new string, which doesn't happen.

the relevant code:

...
.factory('user', function() {
    return {
        name: {str: ''},
        passwordHashed: {str: ''},
        userType: {str: 'none'},
    };
})
.controller('nav', ['$scope', 'user', function($scope, user) {
    $scope.allSites = [
        //example what a page looks like, i have several more pages and several more usertypes
        {name: 'home', title: 'Home', allowed: ['none', 'admin']},
    ];
    $scope.allowedSites = []; //displayed in navigation
    angular.forEach($scope.allSites, function(site) {
        if(contains(site.allowed, user.userType.str) != -1) $scope.allowedSites.push(site);
    });
}])
.controller('loginCTRL', ['$scope', '$http', 'user', function($scope, $http, user) {
    $http.get('url').success(function(data) {

        //some code

        user.name.str = $scope.enteredUsername;
        user.passwordHashed.str = $scope.passwordHashed;
        user.userType.str = data; //admin
    });
});

This is supposed to regenerate the navigation every time the userType changes but after a login for example nothing happens. I've searched around and some posts say, you should put strings into seperate objects but that didn't fix anything. I still kept it (all of this {str: 'bla'} stuff).

If you put some breakpoints in the code of this service (not factory, by the way) and these controllers, you will see that the controllers initialization occurs too 'early', meaning that you don't have the right state for the service yet.

This is because of the dependency injection mechanism.

your controller initiates its state only once. If you want to update its state, you have to put the related code in a refresh() function, and somehow call it where your service is ready.

There are several ways to do this, you can have a look here for instance : http://www.codeproject.com/Tips/773147/Communication-between-the-Controllers-in-AngularJS

Looking at your code here's some advices of how it should be done:

  1. Use $routeProvider with custom attribute like "acl". Use numeric value for it.
  2. Use:

     app.run(function ($rootScope, $location) { $rootScope.$on('$routeChangeStart', function (event, nextRoute, currRoute) { 

    to create redirect interceptor.

  3. Numeric value comparision for ACL attribute: if (user.acl < route.acl)

Clean and simple :)

BTW. You can use $watch in controller to observe changes in factory and react to them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM