$ एक वस्तु देखें


317

मैं एक शब्दकोश में बदलाव देखना चाहता हूं, लेकिन किसी कारण से घड़ी कॉलबैक नहीं कहा जाता है।

यहां एक नियंत्रक है जिसका मैं उपयोग करता हूं:

function MyController($scope) {
    $scope.form = {
        name: 'my name',
        surname: 'surname'
    }

    $scope.$watch('form', function(newVal, oldVal){
        console.log('changed');
    });
}

यहां फिडल है

मुझे उम्मीद है कि हर बार नाम या उपनाम बदले जाने पर $ वॉच कॉलबैक होगा, लेकिन ऐसा नहीं होता है।

इसे करने का सही तरीका क्या है?


जवाबों:


570

कॉल $watchके साथ trueतीसरा तर्क के रूप में:

$scope.$watch('form', function(newVal, oldVal){
    console.log('changed');
}, true);

डिफ़ॉल्ट रूप से जब जावास्क्रिप्ट में दो जटिल वस्तुओं की तुलना करते हैं, तो उन्हें "संदर्भ" समानता के लिए जांचा जाएगा, जो पूछता है कि क्या दो वस्तुएं समान मूल्य के बजाय "मूल्य" समानता को संदर्भित करती हैं, जो उन सभी गुणों के मूल्यों की जांच करती है। वस्तुएं बराबर हैं।

प्रति कोणीय प्रलेखन , तीसरे पैरामीटर के लिए है objectEquality:

जब objectEquality == true, घड़ी की असमानता angular.equalsफ़ंक्शन के अनुसार निर्धारित होती है। बाद की तुलना के लिए ऑब्जेक्ट के मूल्य को बचाने के लिए, angular.copyफ़ंक्शन का उपयोग किया जाता है। इसका मतलब यह है कि जटिल वस्तुओं को देखने से प्रतिकूल स्मृति और प्रदर्शन प्रभाव पड़ेगा।


2
यह एक अच्छा जवाब है, लेकिन मुझे लगता है कि ऐसे समय होते हैं जब आप किसी वस्तु को दोबारा देखना नहीं चाहेंगे
जेसन

16
वहां। डिफ़ॉल्ट रूप से यदि आप पास नहीं करते हैं true, तो यह संदर्भ समानता के लिए जांच करेगा यदि देखे गए मूल्य एक वस्तु या सरणी है। उस स्थिति में, आपको संपत्तियों को स्पष्ट रूप से निर्दिष्ट करना चाहिए, जैसे $scope.$watch('form.name')और$scope.$watch('form.surname')
rossipedia

3
धन्यवाद। ठीक वैसा ही मुझे याद आया। जेसन, आप सही हैं - आप हमेशा पुनरावर्ती वस्तुओं को देखना नहीं चाहते हैं, लेकिन मेरे मामले में यह वही था जो मुझे चाहिए था।
व्लादिमीर सिदोरेंको

1
ImmutableJS और संदर्भ तुलना प्रदर्शन को बढ़ाने में मदद कर सकती है।
ड्रैगोस रूसु

13

formवस्तु को बदलने नहीं है, केवल nameसंपत्ति है

अद्यतन की गई फ़िडल

function MyController($scope) {
$scope.form = {
    name: 'my name',
}

$scope.changeCount = 0;
$scope.$watch('form.name', function(newVal, oldVal){
    console.log('changed');
    $scope.changeCount++;
});
}

12

थोड़ा प्रदर्शन टिप अगर किसी के पास कुंजी के साथ डेटासोर तरह की सेवा है -> मूल्य जोड़े:

यदि आपके पास डेटास्टोर नामक एक सेवा है , तो जब भी आपका बड़ा डेटा ऑब्जेक्ट बदलता है , तो आप टाइमस्टैम्प को अपडेट कर सकते हैं। इस तरह से पूरी वस्तु को देखने के बजाय, आप केवल बदलाव के लिए टाइमस्टैम्प देख रहे हैं।

app.factory('dataStore', function () {

    var store = { data: [], change: [] };

    // when storing the data, updating the timestamp
    store.setData = function(key, data){
        store.data[key] = data;
        store.setChange(key);
    }

    // get the change to watch
    store.getChange = function(key){
        return store.change[key];
    }

    // set the change
    store.setChange = function(key){
        store.change[key] = new Date().getTime();
    }

});

और एक निर्देश में आप केवल बदलने के लिए टाइमस्टैम्प देख रहे हैं

app.directive("myDir", function ($scope, dataStore) {
    $scope.dataStore = dataStore;
    $scope.$watch('dataStore.getChange("myKey")', function(newVal, oldVal){
        if(newVal !== oldVal && newVal){
            // Data changed
        }
    });
});

1
मुझे लगता है कि यह ध्यान देने योग्य है कि इस मामले में आप जो डेटा संग्रहीत कर रहे हैं उसके पुराने मूल्य तक पहुंच की कार्यक्षमता को ढीला कर देंगे। newVal, oldValइस उदाहरण में टाइमस्टैम्प मान नहीं हैं ऑब्जर्व्ड ऑब्जेक्ट्स मान। यह इस उत्तर को अमान्य नहीं बनाता है, मुझे लगता है कि यह एक खामी है जो ध्यान देने योग्य है।
मिशैल शिल्मैन

सच है, इस पद्धति का उपयोग मैं ज्यादातर तब करता हूं जब मैं किसी स्रोत के लिए एक जटिल डेटा संरचना को लोड करना चाहता हूं (उदाहरण के लिए कुछ डेटा का एक नया संस्करण)। अगर मैं नए और पुराने मूल्यों के बारे में परवाह करता हूं तो मैं उन्हें बड़ी जटिल वस्तुओं में संग्रहीत नहीं करूंगा, बल्कि मेरे पास उस चीज का एक छोटा पाठ प्रतिनिधित्व होगा जिसकी मैं देखभाल करता हूं और देखता हूं कि बदलाव के लिए या इसे देखें जब टाइमस्टैम्प बदलता है।
फेरेन टैक्सेस

5

आपके कोड के काम न करने का कारण $watchडिफ़ॉल्ट रूप से संदर्भ जाँच है। अतः संक्षेप में यह सुनिश्चित करें कि जो वस्तु इसे पारित की गई है वह नई वस्तु है। लेकिन आपके मामले में आप सिर्फ फॉर्म ऑब्जेक्ट की कुछ संपत्ति को संशोधित कर रहे हैं जो एक नया निर्माण नहीं कर रहा है। इसे काम करने के लिए आप trueतीसरे पैरामीटर के रूप में पास कर सकते हैं ।

$scope.$watch('form', function(newVal, oldVal){
    console.log('invoked');
}, true);

यह काम करेगा लेकिन आप $ watchCollection का उपयोग कर सकते हैं जो कि अधिक कुशल होगा तब $ watch $watchCollectionहोगा क्योंकि फॉर्म ऑब्जेक्ट पर उथले गुणों के लिए देखेंगे। उदाहरण के लिए

$scope.$watchCollection('form', function (newVal, oldVal) {
    console.log(newVal, oldVal);
});

4

जैसा कि आप प्रपत्र ऑब्जेक्ट परिवर्तनों की तलाश कर रहे हैं, सबसे अच्छा देखने का उपयोग करना है
$watchCollection। विभिन्न प्रदर्शन विशेषताओं के लिए कृपया आधिकारिक दस्तावेज देखें


1

इसे इस्तेमाल करे:

function MyController($scope) {
    $scope.form = {
        name: 'my name',
        surname: 'surname'
    }

    function track(newValue, oldValue, scope) {
        console.log('changed');
    };

    $scope.$watch('form.name', track);
}

0

किसी के लिए जो ऑब्जेक्ट की एक सरणी के भीतर किसी ऑब्जेक्ट में बदलाव के लिए देखना चाहता है, यह मेरे लिए काम करने के लिए लग रहा था (जैसा कि इस पृष्ठ पर अन्य समाधान नहीं किया गया है):

function MyController($scope) {

    $scope.array = [
        data1: {
            name: 'name',
            surname: 'surname'
        },
        data2: {
            name: 'name',
            surname: 'surname'
        },
    ]


    $scope.$watch(function() {
        return $scope.data,
    function(newVal, oldVal){
        console.log(newVal, oldVal);
    }, true);

-3

आपको $ घड़ी में परिवर्तन करना होगा ...।

function MyController($scope) {
    $scope.form = {
        name: 'my name',
    }

    $scope.$watch('form.name', function(newVal, oldVal){
        console.log('changed');
     
    });
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app>
    <div ng-controller="MyController">
        <label>Name:</label> <input type="text" ng-model="form.name"/>
            
        <pre>
            {{ form }}
        </pre>
    </div>
</div>


8
एक दो साल पुराने प्रश्न का उत्तर देने के साथ एक मौजूदा एक के लगभग एक सटीक डुप्लिकेट है? अछा नहीं लगता।
जारेड स्मिथ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.