当从控制器调用的服务更改时,Angular不更新视图

时间:2015-03-28 20:17:23

标签: javascript angularjs angularjs-directive angularjs-scope angularjs-service

似乎当我在指令中使用由控制器调用的服务来更新主控制器中的数组(示例中的MyController)时,Angular不会更新视图。

但是,如果我退出服务,并让指令直接更新数组,那么视图会更新。

(在下面的示例中,我在MyDirectivesController中有两行,一个注释掉哪个版本有效 - 直接更改gridInDirective ....它下面的行调用myService,它确实在本地获取gridInDirective数组,并且似乎在本地更改它,但视图未更新)

如果您运行该示例,则可以单击彩色div,并更改由ng-repeat循环打印的数组元素。

我已尝试在几个地方使用$ scope。$ apply(),但(a)没有工作,(b)我的理解是,只有在我在Angular之外进行更改时才应该这样做......而且我不认为我是。

所以问题是,我如何获得myService中更新的网格版本以更新视图,以及为什么它不像我拥有的​​那样工作?

提前感谢任何花时间看的人。



'use strict';

(function() {
    var ssheet = angular.module('ssheet', []);
    
    ssheet.factory('myService', [function () {
        var myServiceFunction;
        
        return {
            myServiceFunction: function (grid) {
                alert('myServiceFunction');
                alert('grid given to myServiceFunction is ' + grid.toString());
                grid = ['now', 'the', 'grid', 'has', 'changed'];
                alert('grid in myServiceFunction changed to ' + grid.toString());
            } 
        }
    }]);
    
    ssheet.controller('MyController', ['$scope', function ($scope) {
        $scope.gridInMyController = ['foo','bar','dog','cat']; // this was a 2D array, but simplified it for testing
    }]);
    
    ssheet.controller('MyDirectivesController', ['myService', '$scope', function (myService, $scope) {
        $scope.changeGrid = function () {				
            alert('MyDirectivesController.changeGrid');
            //$scope.gridInDirective = ['now', 'the', 'grid', 'has', 'changed']; //this worked
            myService.myServiceFunction($scope.gridInDirective); // this doesn't work
        }
    }]);
    
    ssheet.directive('gridTools', ['myService', function (myService) {       
        return {
            
            restrict: 'E',
            replace: true,
            scope: {
                gridInDirective: '=gridInElement',
            },
            template: '<div class="grid-tools-style" grid-in-element="gridInMyController" ng-click="changeGrid()">Click this div to change the grid</div>',
            
            controller: 'MyDirectivesController',
        }
    }]);
    
})();
&#13;
.grid-tools-style {
    background-color: #c68700;
}

.grid-tools-style:hover {
    cursor: pointer;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="ssheet">
    <div ng-controller="MyController">
        <grid-tools></grid-tools>
        <div ng-repeat="item in gridInMyController"><p>{{item}}</p></div>
    </div>
</body>
&#13;
&#13;
&#13;

3 个答案:

答案 0 :(得分:0)

您可以从指令控制器方法返回新网格,并将其分配给指令网格的范围变量。

请参阅下面的演示以及此jsfiddle

&#13;
&#13;
'use strict';

(function() {
  var ssheet = angular.module('ssheet', []);

  ssheet.factory('myService', [
    function() {
      //var myServiceFunction;

      return {
        myServiceFunction: function(grid) {
          //alert('myServiceFunction');
          //alert('grid given to myServiceFunction is ' + grid.toString());
          grid = ['now', 'the', 'grid', 'has', 'changed'];
          //alert('grid in myServiceFunction changed to ' + grid.toString());
          return grid;
        }
      }
    }
  ]);

  ssheet.controller('MyController', ['$scope',
    function($scope) {
      $scope.gridInMyController = ['foo', 'bar', 'dog', 'cat']; // this was a 2D array, but simplified it for testing
    }
  ]);

  ssheet.controller('MyDirectivesController', ['myService', '$scope',
    function(myService, $scope) {
      $scope.changeGrid = function() {
        //alert('MyDirectivesController.changeGrid');
        //$scope.gridInDirective = ['now', 'the', 'grid', 'has', 'changed']; //this worked
        $scope.gridInDirective = myService.myServiceFunction($scope.gridInDirective); // this doesn't work
        console.log($scope.gridInDirective);
      }
    }
  ]);

  ssheet.directive('gridTools', ['myService',
    function(myService) {
      return {

        restrict: 'E',
        replace: true,
        scope: {
          gridInDirective: '=gridInElement',
        },
        template: '<div class="grid-tools-style" grid-in-element="gridInMyController" ng-click="changeGrid()">Click this div to change the grid</div>',

        controller: 'MyDirectivesController',
      }
    }
  ]);

})();
&#13;
.grid-tools-style {
  background-color: #c68700;
}
.grid-tools-style:hover {
  cursor: pointer;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ssheet">
  <div ng-controller="MyController">
    <grid-tools></grid-tools>
    <div ng-repeat="item in gridInMyController">
      <p>{{item}}</p>
    </div>
  </div>
</div>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

它不起作用的原因是你将数组的引用按值传递给myServiceFunction函数,这意味着你可以修改它的内容,但不能改变对新数组的引用,这基本上就是这一行:

grid = ['now', 'the', 'grid', 'has', 'changed'];

它在指令中起作用的原因是因为你有可用的实际参考,你可以将它改为指向别的东西。

答案 2 :(得分:0)

这是您可以保留引用的方式:

我编写了一个简短的函数,可以将数据放入Object而无需替换它。 您可以在服务中使用它。这样你就不需要使用手表了。您可以使用Angular的正常摘要循环。 例如,看到这个简单的控制器&amp;服务:

演示:JSFidde - http://jsfiddle.net/y09kx7f7/1/ 断言测试

<强>控制器:

app.controller('dem',function($scope,me){
    $scope.user=me.user;   // {name:'user name'}
})

每次更改用户名时,控制器将自动进行无人值守!

<强>服务

.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
})

我写的cloneInto函数:

// 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]
        }
    }
}