$ watch'ing cho các thay đổi dữ liệu trong một lệnh Angular


132

Làm cách nào tôi có thể kích hoạt một $watchbiến trong chỉ thị Angular khi thao tác dữ liệu bên trong (ví dụ: chèn hoặc xóa dữ liệu), nhưng không gán một đối tượng mới cho biến đó?

Tôi có một bộ dữ liệu đơn giản hiện đang được tải từ tệp JSON. Bộ điều khiển góc của tôi thực hiện điều này, cũng như xác định một vài chức năng:

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

    };
});

Tôi có một hàm <button>được gọi đúng là $scope.addhàm và đối tượng mới được chèn đúng vào $scope.datatập hợp. Một bảng tôi đã thiết lập sẽ cập nhật mỗi lần tôi nhấn nút "thêm".

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

Tuy nhiên, một lệnh tôi thiết lập để xem $scope.datasẽ không bị hủy khi tất cả điều này xảy ra.

Tôi xác định thẻ của mình trong HTML:

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

Được liên kết với chỉ thị sau đây (được cắt bớt cho sự tỉnh táo của câu hỏi):

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

Tôi nhận được "I see a data change!"tin nhắn ngay từ đầu, nhưng không bao giờ sau khi tôi nhấn nút "thêm".

Làm cách nào tôi có thể kích hoạt $watchsự kiện khi tôi chỉ thêm / xóa đối tượng khỏi datađối tượng, không nhận toàn bộ dữ liệu mới để gán cho datađối tượng?


5
Chỉ là một mẹo nhanh nếu newValue bao giờ bằng 0, sai, "" hoặc bất cứ điều gì khác giống như vậy "Tôi thấy một sự thay đổi dữ liệu!" sẽ không bắn. Chẳng hạn, giá trị ban đầu là true, newValue là false. Chỉ cần sử dụng newValue trong đó là đủ, đồng hồ đó chỉ được gọi nếu có gì đó thay đổi. Nếu đó là một đối tượng, nó sẽ được gọi ngay lập tức.
Mathew Berg

Mẹo hay, cảm ơn bạn! Tôi sẽ chuyển lên các iftuyên bố.
Evil Closet Monkey

Câu trả lời:


218

Bạn cần phải cho phép kiểm tra bẩn đối tượng sâu. Theo mặc định góc chỉ kiểm tra tham chiếu của biến cấp cao nhất mà bạn xem.

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

xem Phạm vi . Tham số thứ ba của chức năng $ watch cho phép kiểm tra bẩn sâu nếu nó được đặt thành đúng.

Hãy lưu ý rằng kiểm tra bẩn sâu là tốn kém . Vì vậy, nếu bạn chỉ cần xem mảng con thay vì toàn bộ databiến, hãy xem biến trực tiếp.

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

phiên bản 1.2.x được giới thiệu $ watchCollection

Shallow xem các thuộc tính của một đối tượng và kích hoạt bất cứ khi nào bất kỳ thuộc tính nào thay đổi (đối với mảng, điều này ngụ ý xem các mục mảng; đối với bản đồ đối tượng, điều này ngụ ý xem các thuộc tính)

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

1
Làm việc tuyệt vời. Cảm ơn bạn!
Evil Closet Monkey

1
Vui mừng được giúp đỡ. Hãy tiếp tục thử nghiệm chức năng $ watch vì các biểu thức mà nó có thể xem khá đa dạng.
Liviu T.

1
Cảm ơn bạn đã lưu ý cách chỉ kiểm tra các mảng sâu;)
veritas

Thật đáng tiếc tôi không thể nâng cao hơn một lần .. Tôi sẽ cho bạn một tiền thưởng, trong 2 giờ tôi đã mất để tìm kiếm điều đó.
Alex Arvanitidis

câu trả lời tốt nhất hiện có
chovy

2

Bởi vì nếu bạn muốn kích hoạt dữ liệu của mình sâu hơn, bạn phải vượt qua đối số thứ 3 truecủa người nghe. Mặc định false, nó sẽ báo hiệu rằng chức năng của bạn sẽ kích hoạt, chỉ khi biến của bạn thay đổi không phải là trường .


1

Phiên bản của tôi cho một lệnh sử dụng jqplot để vẽ dữ liệu một khi nó có sẵn:

    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));
                }
            });
        }
});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.