Bir Angular yönergesinde veri değişiklikleri için $ watch'ing


132

$watchBir Angular direktifindeki bir değişkeni içerideki verileri işlerken (örneğin, veri eklerken veya çıkarırken) nasıl tetikleyebilirim , ancak bu değişkene yeni bir nesne atamıyorum?

Şu anda bir JSON dosyasından yüklenmekte olan basit bir veri kümem var. Angular denetleyicim bunu yapar ve birkaç işlevi tanımlar:

App.controller('AppCtrl', function AppCtrl($scope, JsonService) {
    // load the initial data model
    if (!$scope.data) {
        JsonService.getData(function(data) {
            $scope.data = data;
            $scope.records = data.children.length;
        });
    } else {
        console.log("I have data already... " + $scope.data);
    }

    // adds a resource to the 'data' object
    $scope.add = function() {
        $scope.data.children.push({ "name": "!Insert This!" });
    };

    // removes the resource from the 'data' object
    $scope.remove = function(resource) {
        console.log("I'm going to remove this!");
        console.log(resource);
    };

    $scope.highlight = function() {

    };
});

İşlevi <button>düzgün bir şekilde çağıran bir o var $scope.addve yeni nesne $scope.datasete düzgün şekilde yerleştirilmiş . "Ekle" düğmesine her bastığımda kurduğum bir tablo güncelleniyor.

<table class="table table-striped table-condensed">
  <tbody>
    <tr ng-repeat="child in data.children | filter:search | orderBy:'name'">
      <td><input type="checkbox"></td>
      <td>{{child.name}}</td>
      <td><button class="btn btn-small" ng-click="remove(child)" ng-mouseover="highlight()"><i class="icon-remove-sign"></i> remove</button></td>
    </tr>
  </tbody>
</table>

Ancak, izlemek için kurduğum bir yönerge $scope.datatüm bunlar olduğunda ateşlenmiyor.

Etiketimi HTML'de tanımlıyorum:

<d3-visualization val="data"></d3-visualization>

Hangisi aşağıdaki direktifle ilişkilidir (soru mantığı için kırpılmıştır):

App.directive('d3Visualization', function() {
    return {
        restrict: 'E',
        scope: {
            val: '='
        },
        link: function(scope, element, attrs) {
            scope.$watch('val', function(newValue, oldValue) {
                if (newValue)
                    console.log("I see a data change!");
            });
        }
    }
});

"I see a data change!"Mesajı en başta alıyorum, ancak "ekle" düğmesine bastığımdan sonra asla.

Nesneye atamak için tamamen yeni bir veri kümesi almadığım $watchhalde datanesneden yalnızca nesne eklerken / kaldırırken olayı nasıl tetikleyebilirim data?


5
NewValue eşittir 0, false "" veya "Bir veri değişikliği görüyorum!" ateş etmeyecek. Örneğin, orijinal değer true, newValue ise false. Orada sadece newValue kullanmak yeterli olmalı, o saat sadece bir şey değiştiğinde çağrılır. Bir nesneyse, anında çağrılacaktır.
Mathew Berg

İyi ipucu, teşekkürler! İfadeyi değiştireceğim if.
Evil Closet Monkey

Yanıtlar:


218

Derin nesne kirli denetimini etkinleştirmeniz gerekir. Varsayılan olarak açısal, yalnızca izlediğiniz en üst düzey değişkenin referansını kontrol eder.

App.directive('d3Visualization', function() {
    return {
        restrict: 'E',
        scope: {
            val: '='
        },
        link: function(scope, element, attrs) {
            scope.$watch('val', function(newValue, oldValue) {
                if (newValue)
                    console.log("I see a data change!");
            }, true);
        }
    }
});

bkz. Kapsam . $ Watch işlevinin üçüncü parametresi, true olarak ayarlanmışsa derin ve kirli denetimi etkinleştirir.

Derin kirli kontrolün pahalı olduğunu unutmayın . Dolayısıyla, tüm datadeğişken yerine sadece çocuk dizisini izlemeniz gerekiyorsa, değişkeni doğrudan izleyin.

scope.$watch('val.children', function(newValue, oldValue) {}, true);

1.2.x sürümü $ watchCollection'ı tanıttı

Shallow, bir nesnenin özelliklerini izler ve özelliklerden herhangi biri değiştiğinde tetiklenir (diziler için bu, dizi öğelerinin izlenmesi anlamına gelir; nesne haritaları için bu, özelliklerin izlenmesi anlamına gelir)

scope.$watchCollection('val.children', function(newValue, oldValue) {});

1
Harika çalışıyor. Teşekkür ederim!
Evil Closet Monkey

1
Yardımcı olduğuma sevindim. İzleyebileceği ifadeler oldukça çeşitli olduğundan, $ watch işlevini denemeye devam edin.
Liviu T.

1
Yalnızca derin dizileri nasıl kontrol edeceğinizi belirttiğiniz için teşekkürler;)
veritas

Yazık ki, birden fazla oy veremem .. Sana bir ödül verirdim, 2 saat boyunca onu ararken kaybettiğim için.
Alex Arvanitidis

en iyi yanıt orada.
chovy

2

Çünkü verilerinizi derinlemesine tetiklemek istiyorsanız true, dinleyicinizin 3. argümanını geçmek zorundasınız.Varsayılan olarak bu, falseişlevinizin tetikleyeceği anlamına gelir, yalnızca değişkeniniz alanını değiştirmeyeceği zaman .


1

Kullanılabilir olduktan sonra verileri çizmek için jqplot kullanan bir yönerge için sürümüm:

    app.directive('lineChart', function() {
        $.jqplot.config.enablePlugins = true;

        return function(scope, element, attrs) {
            scope.$watch(attrs.lineChart, function(newValue, oldValue) {
                if (newValue) {
                    // alert(scope.$eval(attrs.lineChart));
                    var plot = $.jqplot(element[0].id, scope.$eval(attrs.lineChart), scope.$eval(attrs.options));
                }
            });
        }
});
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.