मैं इस सवाल पर कुछ इसी तरह की तलाश में ठोकर खाई, लेकिन मुझे लगता है कि यह क्या हो रहा है, साथ ही कुछ अतिरिक्त समाधानों के बारे में पूरी तरह से स्पष्टीकरण के योग्य है।
जब एक कोणीय अभिव्यक्ति आपके द्वारा उपयोग किए एचटीएमएल में मौजूद है, जैसे कोणीय स्वचालित रूप से एक सेट $watchके लिए $scope.foo, और जब भी एचटीएमएल अद्यतन करेगा $scope.fooबदल जाता है।
<div ng-controller="FooCtrl">
<div ng-repeat="item in foo">{{ item }}</div>
</div>
यहां मुद्दा यह है कि दो चीजों में से एक को प्रभावित कर रहा है aService.foo जैसे कि परिवर्तन पूर्ववत हैं। ये दो संभावनाएँ हैं:
aService.foo हर बार एक नए सरणी में सेट हो रहा है, जिससे इसका संदर्भ पुराना हो गया है।
aService.fooइस तरह से अद्यतन किया जा रहा है कि अद्यतन पर एक $digestचक्र ट्रिगर नहीं होता है।
समस्या 1: उल्लिखित संदर्भ
पहली संभावना को देखते हुए, यह मानते हुए कि $digestलागू किया जा रहा है, अगर aService.fooहमेशा एक ही सरणी होती थी, तो स्वचालित रूप से सेट$watch परिवर्तनों का पता लगाएगा, जैसा कि नीचे दिए गए कोड स्निपेट में दिखाया गया है।
समाधान 1-ए: सुनिश्चित करें कि प्रत्येक अद्यतन पर सरणी या वस्तु एक ही वस्तु है
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है, लेकिन एनजी-रिपीट इससे जुड़ा होता aService2.foo है । इसका कारण यह है कि हमारा संदर्भ aService.fooपुराना है, लेकिन हमारा संदर्भ पुराना aService2.fooनहीं है। हमने प्रारंभिक सरणी के साथ एक संदर्भ बनाया $scope.foo = aService.foo;था, जिसे तब सेवा द्वारा खारिज कर दिया गया था, यह अगले अद्यतन पर है, जिसका अर्थ है$scope.foo अब उस सरणी को संदर्भित नहीं अब हम चाहते थे।
हालांकि, हालांकि यह सुनिश्चित करने के लिए कई तरीके हैं कि प्रारंभिक संदर्भ को चातुर्य में रखा जाए, कभी-कभी वस्तु या सरणी को बदलना आवश्यक हो सकता है। या फिर क्या हुआ अगर सेवा संपत्ति संदर्भ एक तरह एक आदिम Stringया Number? उन मामलों में, हम केवल एक संदर्भ पर भरोसा नहीं कर सकते। तो हम क्या कर सकते हैं?
पहले दिए गए जवाबों में से कई उस समस्या के लिए कुछ समाधान देते हैं। हालांकि, मैं व्यक्तिगत रूप से जिन और thetallweeks द्वारा सुझाई गई सरल पद्धति का उपयोग करने के लिए टिप्पणी में हूं :
html मार्कअप में बस aService.foo का संदर्भ लें
समाधान 1-बी: सेवा को गुंजाइश में संलग्न करें, और {service}.{property}HTML में संदर्भ ।
मतलब, बस यह करें:
HTML:
<div ng-controller="FooCtrl">
<div ng-repeat="item in aService.foo">{{ item }}</div>
</div>
जे एस:
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चक्र लगाया जा रहा है। उपरोक्त मेरे उदाहरणों में, मैंने $intervalसरणियों को अद्यतन करने के लिए कोणीय सेवा का उपयोग किया , जो $digestप्रत्येक अद्यतन के बाद स्वचालित रूप से एक लूप को बंद कर देता है । लेकिन अगर सेवा चर (जो भी कारण से) "कोणीय दुनिया" के अंदर अद्यतन नहीं हो रहे हैं, तो क्या होगा। दूसरे शब्दों में, हम न एक है $digestचक्र स्वचालित रूप से सक्रिय किया जा रहा है जब भी सेवा संपत्ति बदलता है?
यहाँ समाधान में से कई इस मुद्दे को हल करेंगे, लेकिन मैं कोड व्हिस्परर से सहमत हूं :
यही कारण है कि हम एंगुलर जैसे ढांचे का उपयोग कर रहे हैं, अपने स्वयं के पर्यवेक्षक पैटर्न को नहीं पकाना है
इसलिए, मैं उपयोग करना जारी रखना पसंद करूंगा aService.foo HTML मार्कअप में संदर्भ जैसा कि ऊपर दिए गए दूसरे उदाहरण में दिखाया गया है, और नियंत्रक के भीतर अतिरिक्त कॉलबैक दर्ज नहीं करना है।
समाधान 2: सेटर और गेट्टर का उपयोग करें $rootScope.$apply()
मैं हैरान था कि किसी ने अभी तक एक सेटर और गेट्टर के उपयोग का सुझाव नहीं दिया है । इस क्षमता को ECMAScript5 में पेश किया गया था, और इस तरह से यह अब सालों से चली आ रही है। बेशक, इसका मतलब है कि, यदि किसी भी कारण से, आपको वास्तव में पुराने ब्राउज़रों का समर्थन करने की आवश्यकता है, तो यह विधि काम नहीं करेगी, लेकिन मुझे ऐसा लगता है कि गेटर्स और सेटरर्स का जावास्क्रिप्ट में बहुत अधिक उपयोग किया जाता है। इस विशेष मामले में, वे काफी उपयोगी हो सकते हैं:
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>
यहाँ मैंने सेवा फ़ंक्शन में एक 'निजी' चर जोड़ा realFoo:। इस पर क्रमशः कार्यों get foo()और set foo()कार्यों का उपयोग करके अद्यतन और पुनर्प्राप्त किया जाता हैservice ऑब्जेक्ट जाता है।
$rootScope.$apply()सेट फ़ंक्शन के उपयोग पर ध्यान दें । यह सुनिश्चित करता है कि कोणीय किसी भी परिवर्तन से अवगत होगा service.foo। यदि आपको 'इनप्रोग' त्रुटियां मिलती हैं, तो यह उपयोगी संदर्भ पृष्ठ देखें , या यदि आप कोणीय> = 1.3 का उपयोग करते हैं, तो आप इसका उपयोग कर सकते हैं $rootScope.$applyAsync()।
इसके अलावा अगर aService.fooयह बहुत बार अद्यतन किया जा रहा है, तो इससे सावधान रहें , क्योंकि यह प्रदर्शन को काफी प्रभावित कर सकता है। यदि प्रदर्शन एक समस्या होगी, तो आप सेटर का उपयोग करके अन्य उत्तरों के समान एक पर्यवेक्षक पैटर्न सेट कर सकते हैं।