$ bir nesneyi izle


317

Bir sözlükteki değişiklikleri izlemek istiyorum, ancak bir nedenden dolayı geri arama geri çağırılamıyor.

İşte kullandığım bir denetleyici:

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

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

İşte keman .

Adı veya soyadı her değiştiğinde $ watch callback'in tetiklenmesini bekliyorum, ancak gerçekleşmiyor.

Bunu yapmanın doğru yolu nedir?


Yanıtlar:


570

Üçüncü argüman olarak $watchile çağırın true:

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

Varsayılan olarak, JavaScript'teki iki karmaşık nesneyi karşılaştırırken, bu nesnelerin tüm özelliklerinin değerlerinin olup olmadığını kontrol eden "değer" eşitliği yerine aynı değere karşılık gelip gelmediğini soran "başvuru" eşitliği için denetlenir. nesneler eşittir.

Başına Eğik belgeler , üçüncü parametre içindir objectEquality:

Zaman objectEquality == true, watchExpression eşitsizliği göre belirlenir angular.equalsfonksiyonu. Nesnenin değerini daha sonra karşılaştırılmak üzere kaydetmek için angular.copyişlev kullanılır. Bu nedenle, karmaşık nesneleri izlemenin olumsuz bellek ve performans etkileri olacağı anlamına gelir.


2
Bu iyi bir cevap, ama bir nesneyi tekrar tekrar izlemek istemeyeceğiniz zamanlar olduğunu hayal ediyorum
Jason

16
Var. Varsayılan olarak truegeçmezseniz, izlenen değerin bir nesne veya dizi olup olmadığı referans eşitliğini kontrol eder. Bu durumda, özellikleri açıkça belirtmelisiniz, $scope.$watch('form.name')ve$scope.$watch('form.surname')
rossipedia

3
Teşekkürler. Tam da bunu kaçırdım. Jason, haklısın - her zaman özyinelemeli nesneleri izlemek istemezsin, ama benim durumumda tam olarak ihtiyacım olan şeydi.
Vladimir Sidorenko

1
ImmutableJS ve referans karşılaştırması performansı artırmaya yardımcı olabilir.
Dragos Rusu

13

formNesnesi, yalnızca, değişmiyor nameözelliktir

güncellenmiş keman

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

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

12

Birinin anahtar -> değer çiftleri ile bir veri deposu türü hizmeti varsa küçük performans ipucu :

DataStore adlı bir hizmetiniz varsa, büyük veri nesneniz her değiştiğinde bir zaman damgasını güncelleyebilirsiniz . Bu şekilde, tüm nesneyi derinlemesine izlemek yerine, sadece değişim için bir zaman damgası izliyorsunuz.

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();
    }

});

Ve bir direktifte sadece değiştirmek için zaman damgasını izliyorsunuz

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

1
Bu durumda depoladığınız verilerin eski değerine erişme işlevini kaybedeceğinizi belirtmek gerekir. newVal, oldValbu örnekte, gözlemlenen nesne değerleri değil zaman damgası değerleri verilmiştir. Bu cevabı geçersiz kılmaz, sadece bahsetmeye değer bir dezavantaj olduğunu düşünüyorum.
Michał Schielmann

Doğru, bu yöntem çoğunlukla karmaşık bir veri yapısını bir şey (örneğin bazı verilerin yeni bir sürümü) kaynağı olarak yüklemek istediğinizde kullanıyorum. Yeni ve eski değerleri umursam, onları büyük karmaşık nesnelerde saklamamıştım, bunun yerine umurumda olduğum şeyin küçük bir metin temsilini ve zaman damgası değiştiğinde bunu değiştirmek veya almak için izlerdim.
Ferenc Takacs

5

Kodunuzun çalışmamasının nedeni $watch, varsayılan olarak başvuru denetimidir. Kısacası, kendisine aktarılan nesnenin yeni nesne olduğundan emin olun. Ancak sizin durumunuzda, yeni bir nesne oluşturmayan form nesnesinin bazı özelliklerini değiştiriyorsunuzdur. Çalışması trueiçin üçüncü parametre olarak geçebilirsiniz .

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

Çalışır, ancak $ watchCollection kullanabilirsiniz $ watch sonra daha verimli $watchCollectionolacaktır çünkü form nesnesinde sığ özellikleri izleyecektir. Örneğin

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

4

Form nesnesi değişikliklerini ararken, en iyi izleme yaklaşımı kullanmaktır
$watchCollection. Lütfen farklı performans özellikleri için resmi belgelere göz atın .


1

Bunu dene:

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

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

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

0

Bir nesne dizisindeki bir nesnede bir değişiklik izlemek isteyen herkes için, bu benim için işe yaramış gibi görünüyordu (bu sayfadaki diğer çözümler işe yaramadı gibi):

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

$ watch değişmelisiniz ....

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
İki yıllık bir soruyu, var olan sorunun neredeyse aynısı olan bir cevapla mı cevaplıyorsunuz? Hiç hoş değil.
Jared Smith
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.