Angular 当从控制器调用的服务更改时不更新视图
Angular not updating view when changed by service called from controller
似乎当我在指令中使用由控制器调用的服务来更新主控制器(示例中的 MyController)中的数组时,Angular 不会更新视图。
但是,如果我将服务排除在外,让指令直接更新数组,那么视图就会更新。
(在下面的示例中,在 MyDirectivesController 中有 2 行,其中一行被注释掉了,这是有效的版本 - 直接更改 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',
}
}]);
})();
.grid-tools-style {
background-color: #c68700;
}
.grid-tools-style:hover {
cursor: pointer;
}
<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>
您可以 return 指令控制器方法中的新网格并将其分配给指令网格的范围变量。
请参阅下面和此 jsfiddle 中的演示。
'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',
}
}
]);
})();
.grid-tools-style {
background-color: #c68700;
}
.grid-tools-style:hover {
cursor: pointer;
}
<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>
它不起作用的原因是您通过值将数组的引用传递给myServiceFunction
函数,这意味着您可以修改它内容,但不能更改其对新数组的引用,这实际上就是这一行的作用:
grid = ['now', 'the', 'grid', 'has', 'changed'];
它在指令中起作用的原因是因为您有可用的实际引用,您可以将其更改为指向其他内容。
这是您可以保留参考的方法:
我写了一个简短的函数,让您可以将数据放入 Object 而无需替换它。
你可以在你的服务中使用它。这样你就不需要使用手表了。您可以使用 Angular 的正常摘要循环。
例如,查看这个简单的控制器和服务:
演示: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]
}
}
}
似乎当我在指令中使用由控制器调用的服务来更新主控制器(示例中的 MyController)中的数组时,Angular 不会更新视图。
但是,如果我将服务排除在外,让指令直接更新数组,那么视图就会更新。
(在下面的示例中,在 MyDirectivesController 中有 2 行,其中一行被注释掉了,这是有效的版本 - 直接更改 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',
}
}]);
})();
.grid-tools-style {
background-color: #c68700;
}
.grid-tools-style:hover {
cursor: pointer;
}
<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>
您可以 return 指令控制器方法中的新网格并将其分配给指令网格的范围变量。
请参阅下面和此 jsfiddle 中的演示。
'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',
}
}
]);
})();
.grid-tools-style {
background-color: #c68700;
}
.grid-tools-style:hover {
cursor: pointer;
}
<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>
它不起作用的原因是您通过值将数组的引用传递给myServiceFunction
函数,这意味着您可以修改它内容,但不能更改其对新数组的引用,这实际上就是这一行的作用:
grid = ['now', 'the', 'grid', 'has', 'changed'];
它在指令中起作用的原因是因为您有可用的实际引用,您可以将其更改为指向其他内容。
这是您可以保留参考的方法:
我写了一个简短的函数,让您可以将数据放入 Object 而无需替换它。 你可以在你的服务中使用它。这样你就不需要使用手表了。您可以使用 Angular 的正常摘要循环。 例如,查看这个简单的控制器和服务:
演示: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]
}
}
}