나는 비슷한 질문을 찾기 위해이 질문을 우연히 만났지만 진행중인 일과 몇 가지 추가 솔루션에 대한 철저한 설명이 필요하다고 생각합니다.
사용하는 것과 같은 각도 표현식이 HTML에 있으면 Angular는 자동으로 $watch
for를 설정하고 변경 $scope.foo
될 때마다 HTML을 업데이트합니다 $scope.foo
.
<div ng-controller="FooCtrl">
<div ng-repeat="item in foo">{{ item }}</div>
</div>
여기서 언급되지 않은 문제 aService.foo
는 변경 사항이 감지되지 않도록 두 가지 중 하나가 영향을 미친다는 것 입니다. 이 두 가지 가능성은 다음과 같습니다.
aService.foo
매번 새 배열로 설정되어 참조가 오래되었습니다.
aService.foo
업데이트시 $digest
사이클이 트리거되지 않는 방식으로 업데이트됩니다.
문제 1 : 오래된 참조
첫 번째 가능성을 고려할 때, a $digest
가 적용 되었다고 가정 할 때 aService.foo
항상 같은 배열 인 경우 자동 설정$watch
아래 코드 스 니펫에 표시된대로 이 변경 사항을 감지합니다.
해결 방법 1-a : 각 업데이트 에서 배열 또는 객체가 동일한 객체 인지 확인하십시오.
angular.module('myApp', [])
.factory('aService', [
'$interval',
function($interval) {
var service = {
foo: []
};
// Create a new array on each update, appending the previous items and
// adding one new item each time
$interval(function() {
if (service.foo.length < 10) {
var newArray = []
Array.prototype.push.apply(newArray, service.foo);
newArray.push(Math.random());
service.foo = newArray;
}
}, 1000);
return service;
}
])
.factory('aService2', [
'$interval',
function($interval) {
var service = {
foo: []
};
// Keep the same array, just add new items on each update
$interval(function() {
if (service.foo.length < 10) {
service.foo.push(Math.random());
}
}, 1000);
return service;
}
])
.controller('FooCtrl', [
'$scope',
'aService',
'aService2',
function FooCtrl($scope, aService, aService2) {
$scope.foo = aService.foo;
$scope.foo2 = aService2.foo;
}
]);
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="FooCtrl">
<h1>Array changes on each update</h1>
<div ng-repeat="item in foo">{{ item }}</div>
<h1>Array is the same on each udpate</h1>
<div ng-repeat="item in foo2">{{ item }}</div>
</div>
</body>
</html>
당신이 볼 수 있듯이, 가정에 부착 된 겨-반복 aService.foo
할 때 업데이트되지 않습니다 aService.foo
변화를, 그러나에 부착 된 NG-반복 aService2.foo
않습니다 . 우리에 대한 언급 aService.foo
이 오래되었지만 우리에 대한 언급 aService2.foo
이 그렇지 않기 때문입니다. 를 사용하여 초기 배열에 대한 참조를 만든 $scope.foo = aService.foo;
다음 다음 업데이트에서 서비스에 의해 삭제되었습니다.$scope.foo
더 이상 원하는 배열을 더 이상 참조하지 않았습니다.
그러나 초기 참조를 그대로 유지하는 몇 가지 방법이 있지만 때로는 개체 나 배열을 변경해야 할 수도 있습니다. 또는 서비스 속성이 a String
또는 Number
? 이 경우 단순히 참조에 의존 할 수 없습니다. 그래서 우리는 무엇 을 할 수 있습니까?
이전에 제공된 몇 가지 답변은 이미 해당 문제에 대한 해결책을 제시합니다. 그러나 개인적으로 Jin 과 thetallweeks 가 제안한 간단한 방법을 의견에 개인적으로 찬성 합니다.
html 마크 업에서 aService.foo를 참조하십시오.
솔루션 1-b : 서비스를 범위에 첨부 {service}.{property}
하고 HTML에서 참조 하십시오.
의미, 그냥 이렇게 :
HTML :
<div ng-controller="FooCtrl">
<div ng-repeat="item in aService.foo">{{ item }}</div>
</div>
JS :
function FooCtrl($scope, aService) {
$scope.aService = aService;
}
angular.module('myApp', [])
.factory('aService', [
'$interval',
function($interval) {
var service = {
foo: []
};
// Create a new array on each update, appending the previous items and
// adding one new item each time
$interval(function() {
if (service.foo.length < 10) {
var newArray = []
Array.prototype.push.apply(newArray, service.foo);
newArray.push(Math.random());
service.foo = newArray;
}
}, 1000);
return service;
}
])
.controller('FooCtrl', [
'$scope',
'aService',
function FooCtrl($scope, aService) {
$scope.aService = aService;
}
]);
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js@1.4.7" data-semver="1.4.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="FooCtrl">
<h1>Array changes on each update</h1>
<div ng-repeat="item in aService.foo">{{ item }}</div>
</div>
</body>
</html>
그 방법은이 $watch
해결됩니다 aService.foo
각$digest
올바르게 업데이트 된 값을 얻습니다.
이것은 당신이 당신의 해결 방법과 관련이 있었지만, 훨씬 덜 둥근 형태입니다. 당신은 불필요한 추가 $watch
명시 적으로두고 컨트롤러에 foo
온 $scope
이 변경 될 때마다. 당신은 그 여분 필요하지 않습니다 $watch
당신이 연결할 때 aService
대신 aService.foo
받는 $scope
바인드 명시하고, aService.foo
마크 업에.
이제 $digest
사이클이 적용되는 것으로 가정하면 충분 합니다. 위의 예제에서 Angular의 $interval
서비스를 사용하여 배열을 $digest
업데이트했습니다. 각 업데이트 후 루프 가 자동으로 시작됩니다 . 그러나 어떤 이유로 든 서비스 변수가 "Angular World"내에서 업데이트되지 않으면 어떻게 될까요? 즉, 우리가 해달라고 이 $digest
서비스의 속성이 변경 될 때마다주기가 자동으로 활성화되고?
여기에있는 많은 솔루션 이이 문제를 해결할 것이지만 Code Whisperer에 동의합니다 .
우리가 Angular와 같은 프레임 워크를 사용하는 이유는 우리 자신의 관찰자 패턴을 요리하지 않기 위해서입니다.
따라서 aService.foo
위의 두 번째 예와 같이 HTML 마크 업에서 참조 를 계속 사용 하고 Controller 내에 추가 콜백을 등록 할 필요가 없습니다.
해결책 2 : 세터와 게터를 $rootScope.$apply()
아직 아무도 setter 와 getter 의 사용을 제안하지 않은 것에 놀랐습니다 . 이 기능은 ECMAScript5에 도입되어 몇 년 전부터 사용되었습니다. 물론, 어떤 이유로 든 오래된 브라우저를 지원 해야하는 경우이 방법이 작동하지 않지만 getter 및 setter가 JavaScript에서 많이 사용되지 않는 것 같습니다. 이 특별한 경우에는 매우 유용 할 수 있습니다.
factory('aService', [
'$rootScope',
function($rootScope) {
var realFoo = [];
var service = {
set foo(a) {
realFoo = a;
$rootScope.$apply();
},
get foo() {
return realFoo;
}
};
// ...
}
angular.module('myApp', [])
.factory('aService', [
'$rootScope',
function($rootScope) {
var realFoo = [];
var service = {
set foo(a) {
realFoo = a;
$rootScope.$apply();
},
get foo() {
return realFoo;
}
};
// Create a new array on each update, appending the previous items and
// adding one new item each time
setInterval(function() {
if (service.foo.length < 10) {
var newArray = [];
Array.prototype.push.apply(newArray, service.foo);
newArray.push(Math.random());
service.foo = newArray;
}
}, 1000);
return service;
}
])
.controller('FooCtrl', [
'$scope',
'aService',
function FooCtrl($scope, aService) {
$scope.aService = aService;
}
]);
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="FooCtrl">
<h1>Using a Getter/Setter</h1>
<div ng-repeat="item in aService.foo">{{ item }}</div>
</div>
</body>
</html>
서비스 기능에 'private'변수를 추가했습니다 realFoo
. 이 함수 는에서 get foo()
및 set foo()
함수를 각각 사용하여 업데이트 및 검색 됩니다.service
객체 .
$rootScope.$apply()
설정 기능에서 의 사용에 유의하십시오 . 이를 통해 Angular는에 대한 변경 사항을 인식 할 수 있습니다 service.foo
. 'inprog'오류가 발생 하면이 유용한 참조 페이지를 참조 하거나 Angular> = 1.3을 사용하면을 사용할 수 있습니다 $rootScope.$applyAsync()
.
aService.foo
성능이 크게 저하 될 수 있으므로 매우 자주 업데이트되는 경우에도주의하십시오 . 성능이 문제가된다면, setter를 사용하여 다른 답변과 비슷한 관찰자 패턴을 설정할 수 있습니다.