$ menonton perubahan data dalam arahan Angular

132

Bagaimana saya bisa memicu $watchvariabel dalam arahan sudut ketika memanipulasi data di dalamnya (misalnya, memasukkan atau menghapus data), tetapi tidak menetapkan objek baru ke variabel itu?

Saya memiliki dataset sederhana yang sedang dimuat dari file JSON. Pengontrol Angular saya melakukan ini, serta mendefinisikan beberapa fungsi:

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() {

    };
});

Saya memiliki fungsi <button>yang disebut dengan benar $scope.add, dan objek baru dimasukkan dengan benar ke dalam $scope.datahimpunan. Tabel yang saya atur tidak memperbarui setiap kali saya menekan tombol "add".

<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>

Namun, arahan yang saya atur untuk menonton $scope.datatidak dipecat ketika semua ini terjadi.

Saya mendefinisikan tag saya dalam HTML:

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

Yang dikaitkan dengan arahan berikut (dipangkas untuk kewarasan pertanyaan):

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!");
            });
        }
    }
});

Saya mendapatkan "I see a data change!"pesan di awal, tetapi tidak pernah setelah saya menekan tombol "add".

Bagaimana saya bisa memicu $watchacara ketika saya hanya menambahkan / menghapus objek dari dataobjek, tidak mendapatkan dataset baru untuk ditugaskan ke dataobjek?

Monyet Lemari Jahat
sumber
5
Hanya tip singkat jika newValue pernah sama dengan 0, false, "" atau yang lain seperti itu, "Saya melihat perubahan data!" tidak akan menembak. Misalnya, nilai asli benar, nilai baru salah. Seharusnya cukup dengan hanya menggunakan newValue di sana, arloji itu hanya dipanggil jika ada sesuatu yang berubah. Jika itu objek, itu akan dipanggil langsung.
Mathew Berg
Tip yang bagus, terima kasih! Saya akan beralih ifpernyataan itu.
Evil Closet Monkey

Jawaban:

218

Anda harus mengaktifkan pemeriksaan kotor objek yang dalam. Secara default sudut hanya memeriksa referensi dari variabel tingkat atas yang Anda tonton.

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

lihat Lingkup . Parameter ketiga dari fungsi $ watch memungkinkan pemeriksaan kotor dalam jika disetel ke true.

Perhatikan bahwa pemeriksaan yang dalam sangat mahal . Jadi jika Anda hanya perlu menonton array anak-anak alih-alih seluruh datavariabel menonton variabel langsung.

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

versi 1.2.x memperkenalkan $ watchCollection

Dangkal menonton properti dari suatu objek dan menyala setiap kali salah satu properti berubah (untuk array, ini berarti menonton item array; untuk peta objek, ini berarti menonton properti)

scope.$watchCollection('val.children', function(newValue, oldValue) {});
Liviu T.
sumber
1
Bekerja dengan baik. Terima kasih!
Evil Closet Monkey
1
Senang untuk membantu. Terus bereksperimen dengan fungsi $ watch karena ekspresi yang dapat ditontonnya cukup bervariasi.
Liviu T.
1
Terima kasih telah memperhatikan cara memeriksa hanya array yang dalam;)
veritas
Sangat disayangkan saya tidak dapat memilih lebih dari satu kali .. Saya akan memberi Anda hadiah, untuk 2h saya kehilangan mencari itu.
Alex Arvanitidis
jawaban terbaik di luar sana.
chovy
2

Karena jika Anda ingin memicu data Anda dengan dalamnya, Anda harus melewati argumen ke 3 truependengar Anda. Secara default itu falsedan itu berarti Anda berfungsi akan memicu, hanya ketika variabel Anda akan berubah bukan bidangnya .

Hazarapet Tunanyan
sumber
1

Versi saya untuk arahan yang menggunakan jqplot untuk memplot data begitu tersedia:

    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));
                }
            });
        }
});
rob2universe
sumber