AngularJS:为什么只能绑定参考值而不是服务的原始值?

时间:2014-12-17 04:35:27

标签: angularjs primitive-types angular-services reference-type

我创建了一个plunker来测试服务上的绑定$scope。我发现我只能绑定到原始值,但引用服务的值。

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.7/angular.min.js"></script>
<body ng-app="BindToService">

    <div ng-controller="BindToServiceCtrl as ctrl">
        // I wonder why I could only bind on reference but primitive values of a service.
        counterFactoryObj: {{counterFactoryObj}}<br/>
        counterFactoryVal: {{counterFactoryVal}}<br/>
        counterFactoryFun(): {{counterFactoryFun()}}<br/>
    </div>

    <script type="text/javascript">
        var app = angular.module("BindToService", []);

        app.controller("BindToServiceCtrl", function ($scope, CounterFactory) {
          $scope.counterFactoryObj = CounterFactory.obj;
          $scope.counterFactoryVal = CounterFactory.val;
          $scope.counterFactoryFun = CounterFactory.fun;
        });

        app.factory("CounterFactory", function ($interval) {
            var obj = [0];
            var val = 0;
            var fun = function () { return val; };

            var addCounter = function () {
                obj[0] += 1;
                val += 1;
            };

            $interval(addCounter, 1000);

            return {
                obj: obj,
                val: val,
                fun: fun
            };
        });
    </script>
</body>

在此演示中,只有counterFactoryObjcounterFactoryFun()会随时间变化。我想知道AngularJS是如何绑定价值的。

1 个答案:

答案 0 :(得分:1)

我认为这里有一些事情会造成混乱。

首先,当您返回一个带有:

的对象时
return {
  val: someVal
}

对象的属性val在您将其返回到someVal的值时设置。因此,当您返回CounterFactory服务时,CounterFactory.val === 0 - 始终 - 并且它与Angular的绑定无关。

其次,使用CounterService服务,您的CounterService实例有this.val,实际上它正在使用$ interval更新(尝试使用console.log)。问题在于,您将其在特定时间点(例如,当控制器函数运行时)的值分配给$scope.counterServiceVal变量。在此处,虽然CounterService.val发生了变化,但仍然如下:$scope.counterServiceVal === 0

顺便说一句,.service.factory就Angular而言都返回一个单例服务实例,除了一个返回一个新的函数而另一个 - 实际的实例,但是与Angular获取实际服务实例的内容有关 - 在注入服务之后它的行为方式相同。

最后,如果你想绑定一个值 - 你可以,但是你需要实际改变那个值并绑定到那个变化的变量。以下是您使用CounterFactory执行此操作的方法,例如:

app.factory("CounterService", function ($interval) {
    var svc = { val: 0 };

    function addCounter() {
        svc.val += 1;
    };

    $interval(addCounter, 1000);

    return svc;
});

// in controller
$scope.counterService = CounterService;

<!-- in the view -->
<span>{{counterService.val}}</span>