无法在setInterval操作上绑定值

时间:2017-03-09 19:18:54

标签: javascript angularjs

我试图用2个控制器和2个服务创建一个简单的例子,其中一个服务每3秒调用一次。

controller1调用服务,该服务更改controller2中使用的值。我将值传递给另一个服务,但是只有在我按下“停止”后,我的html页面上的值才会更新。我的例子的按钮(在下面)。

我可以在每次投票时更新页面值吗?

<html ng-app="myApp">
<head>
    <title>MyApp</title>
    <script src="angular.js"></script>
    <script>
        var app = angular.module('myApp',[]);


        app.service('SimpleService', function() {

          var _value = 0;

          var setValue = function(v) {
              _value = v;
          }

          var getValue = function(){
              return _value;
          }

          return {
            setValue: setValue,
            getValue: getValue
          };
        })

        app.service('PollService', function(SimpleService) {

          var poll = undefined;


            var startPolling = function(){

                poll = setInterval(function(){
                    console.info('poll...');
                    console.info(SimpleService.getValue());
                    SimpleService.setValue(SimpleService.getValue()+1); 

                }, 3000);

            }

            var stopPolling = function(){
                clearInterval(poll);
            }


          return {
            startPolling: startPolling,
            stopPolling: stopPolling
          };
        })


        app.controller('Controller1',function($scope, PollService){
            var poll = undefined;


            $scope.startPolling = function(){
                PollService.startPolling();
            }

            $scope.stopPolling = function(){
                console.info('stop');
                PollService.stopPolling();
            }

        });


        app.controller('Controller2', function($scope, SimpleService){
            $scope.newVal = function(){
                return SimpleService.getValue();
            }               
        });
    </script>

</head>

<body>
    <div ng-controller="Controller1">
        <button ng-click="startPolling()">Start</button>
        <button ng-click="stopPolling()">Stop</button>
        <br/>
        <br/>

    </div>
    <div ng-controller="Controller2">
            <h5>New value: {{newVal()}}</h5>
        </div>

</body>

问候。

2 个答案:

答案 0 :(得分:3)

每次在SimpleService中调用setter时,都需要调用摘要周期。除非新的摘要周期开始,否则视图绑定不会更新。这是工作代码段。

    app.service('SimpleService', function($rootScope) {

      var _value = 0;

      var setValue = function(v) {
          _value = v;
          $rootScope.$apply(); //added this here
      }

      var getValue = function(){
          return _value;
      }

      return {
        setValue: setValue,
        getValue: getValue
      };
    })

你需要做scope.apply()。 $ apply评估模板中的任何表达式并开始一个新的摘要周期。在$ digest阶段,作用域检查所有$ watch表达式并将它们与之前的值进行比较。您可以查看有关它的文档here

我在您的代码中注意到的其他一些问题:

app.controller('Controller2', function($scope, SimpleService2){
  $scope.newVal = function(){
    return SimpleService.getValue();
  }               
});

在此处,将名称更正为SimpleService。

没有stopPropagation方法。我在PollService中按如下方式添加它以使代码正常工作:

var stopPolling = function(){
  clearInterval(poll);
}

答案 1 :(得分:1)

由于setInterval不是一个角度函数,因此angular不知道该值是否已更新,并且无法告诉DOM该值是脏的,因此不会更新。

如果您想继续使用true而不是angular的$ interval,可以将setInterval注入您的投票服务,然后您可以使用$rootScope来消化将更新的值DOM。你可以做到

$rootScope.$apply

$rootScope.$apply(function(){ SimpleService.setValue(SimpleService.getValue()+1); }); 功能中。

否则,setInterval$interval函数的angular.js包装器,不需要手动调用$ apply。

我对您的代码和一些示例进行了更改,以便您可以更好地构建在控制器范围内使用服务的方式。

See here for updated code

主要是,由于服务是一个对象,我们可以通过将服务本身添加到控制器作用域来直接引用DOM中的服务上下文,而不是引用单个对象键。这消除了从DOM调用getter函数的需要(就像调用{{newValue()}}时那样。)