Javascript 角度:通过服务或更好的方法更新不同的控制器

Javascript 角度:通过服务或更好的方法更新不同的控制器,javascript,angularjs,Javascript,Angularjs,我有一个用户服务 angular.module('mango.services', []) .factory('UserService', function() { var user = { id: null, name: 'anonymous.' }; function getUser(){ return user; } functio

我有一个用户服务

angular.module('mango.services', [])
    .factory('UserService', function() {
        var user = {
            id: null,
            name: 'anonymous.'
        };
        function getUser(){
            return user;
        }
        function setUser(val){
            user = val;
        }
        return {
            getUser: getUser,
            setUser: setUser,
        }
});
导航控制器

.controller('NavbarController', ['$scope','$location','UserService', function($scope, $location, UserService){
    $scope.isActive = function (viewLocation) {
        return viewLocation === $location.path();
    };
    $scope.username = UserService.getUser().name;
}])
还有一个UserController,其中有registerUser和logiuser函数

.controller('UserController', ['$scope', '$http', 'UserService', function($scope, $http, UserService) {
   $scope.loginUser = function(){
        $http.post('/api/1.0/user/authenticate', $scope.user)
            .success(function(data,status,headers,config){
                if (data["valid"] === true) {
                    UserService.setUser(data.user);
                } else {
                    $scope.flashes = data.flashes;
                    $scope.user.password = "";
                }
             })
}
还有HTML

        <li ng-switch="username">
            <a ng-class="{ active: isActive('/user/login')}" href="#/user/login" ng-switch-when="anonymous."><i class="fa fa-sign-in"></i> Sign in</a>
            <a ng-class="{ active: isActive('/user/logout')}" href="#/user/logout" ng-switch-default><i class="fa fa-sign-out"></i> Sign out</a>
        </li>
  • 如您所见,如果data.valid为true,我将尝试设置UserService的用户

    服务器正在返回有效的json对象

    但是NavbarController中的用户名值仍然是“匿名的”

    我对JS不是很有经验,但我读了一些关于广播和观看的东西。我相信这可能是正确的方法。但也许有更好的

    我相信它不起作用的原因是因为工厂退回了一个单身汉。但是使用工厂是没有意义的

    所以本质上我想要的是,如果凭据有效,请在客户端应用程序范围内设置user.name user.id。稍后,它应该通过“检查客户端用户是否有效”服务。我的会话cookie已加密。但这超出了问题的范围


    我现在只需要从UserController设置应用程序的用户数据,或者更确切地说是NavbarController的用户数据。如何做到这一点,以便它也会更新DOM aka ng开关以获得不同的值。

    您确实需要一个
    $watch
    er来同步
    NavbarController
    UserService
    中的
    $scope.username=UserService.getUser().name
    仅在初始化控制器时设置
    $scope.username
    的初始值:

    $scope.$watch(
    函数(){return UserService.getUser().name;},
    函数(newVal){
    $scope.username=newVal;
    }
    );
    
    工厂实际上被设计成应用程序中的一个单例,在这里您应该保存应用程序的状态(即您的模型,如
    用户
    模型)。控制器是短暂的,每次创建模板时都会重新创建

    但是,如果您有一个长寿命的控制器(如
    NavbarControll
    ),则使用
    $watch
    在服务和控制器之间保持
    同步的责任在于程序员


    在某些情况下,当需要控制器间通信(不一定涉及
    型号
    )时,广播消息非常有用。

    它不起作用,因为您没有创建某种类型的绑定:使用
    $scope.username=UserService.getUser().name
    您可以在该时刻获得用户名(这是一个匿名的
    )并永远保持它。解决方法之一是使用手表。在NavbarController中,将以前的代码替换为:

    $scope.$watch(
        function() {
            return UserService.getUser().name;
        },
        function(newval) {
            $scope.username = newval;
        }
    );
    
    这将导致您的应用程序在每个摘要周期中调用一个函数。这个函数调用并不慢,所以这无关紧要

    如果您不希望出现这种开销,也可以使用事件来实现。在NavbarController中:

    $scope.username = UserService.getUser().name;
    $scope.on("loggedIn", function(event, newUserName) {
        $scope.username = newUserName;
    });
    
    在UserController中(将
    $rootScope
    添加到依赖项中):

    • 您可以在不使用$watch的情况下使用相同的方法
    我编写了一个简短的函数,让您可以将数据放入对象中,而无需替换它。 您可以在您的服务中使用它。这样您就不需要使用手表。您可以使用Angular的正常摘要循环。 例如,请参见以下简单控制器和服务:

    演示:JSFidde-带有断言测试

    控制器:

    app.controller('dem',function($scope,me){
        $scope.user=me.user;   // {name:'user name'}
    })
    
    // The function it is like a=b, 
    // but keeping the object in his original memory position.
    function cloneInto(a,b){
        var i
        for (i in a){
            if(typeof a[i]!='object') //For supporting deep-copy
               delete a[i]
        }
        for (i in b){
            if (typeof b[i]=='object'){
                if(!a[i]) a[i]={}
                cloneInto(a[i],b[i])
            }
            else{
                a[i]=b[i]
            }
        }
    }
    
    每次更改用户名时,控制器将自动更改,无需监视

    服务

    .factory('me',function($timeout){
        var obj={}
        obj.user={name:'hello'}
        $timeout(function(){  //Example of change the data
            newUser={name:'israel'}
            cloneInto(obj.user,newUser)
        },1000)
        return obj
    })
    
    我编写的克隆函数:

    app.controller('dem',function($scope,me){
        $scope.user=me.user;   // {name:'user name'}
    })
    
    // The function it is like a=b, 
    // but keeping the object in his original memory position.
    function cloneInto(a,b){
        var i
        for (i in a){
            if(typeof a[i]!='object') //For supporting deep-copy
               delete a[i]
        }
        for (i in b){
            if (typeof b[i]=='object'){
                if(!a[i]) a[i]={}
                cloneInto(a[i],b[i])
            }
            else{
                a[i]=b[i]
            }
        }
    }
    

    你试过使用服务而不是工厂吗?我相信服务使用单个对象,而工厂每次注入都会生成新的引用。谢谢,我选择Nikos one是因为它也有广播示例(比你快3分钟).我还没决定..因为你解释得更好。所以我同意了他的答案,并对你的答案投了更高的票~@user2312578当然,不过你也应该对他的答案投更高的票。而且,我不确定你是否正确计算出谁更快。:)谢谢,事件是更好的解决方案$广播和$on类似于我熟悉的Qt的信号/插槽。