$ xem một đối tượng


317

Tôi muốn xem các thay đổi trong từ điển, nhưng vì một số lý do, gọi lại không được gọi.

Đây là một bộ điều khiển mà tôi sử dụng:

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

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

Đây là bí ẩn .

Tôi hy vọng cuộc gọi lại $ watch sẽ bị hủy mỗi lần thay đổi tên hoặc họ, nhưng điều đó không xảy ra.

Cách chính xác để làm điều đó là gì?


Câu trả lời:


570

Gọi $watchvới truetư cách là đối số thứ ba:

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

Theo mặc định khi so sánh hai đối tượng phức tạp trong JavaScript, chúng sẽ được kiểm tra tính bằng "tham chiếu", hỏi xem hai đối tượng có tham chiếu cùng một thứ không, thay vì bằng "giá trị", kiểm tra xem các giá trị của tất cả các thuộc tính của các thuộc tính đó các đối tượng bằng nhau.

Theo tài liệu Angular , tham số thứ ba dành cho objectEquality:

Khi objectEquality == true, bất đẳng thức của watchExpression được xác định theo angular.equalschức năng. Để lưu giá trị của đối tượng để so sánh sau, angular.copyhàm được sử dụng. Do đó, điều này có nghĩa là việc xem các đối tượng phức tạp sẽ có tác động bất lợi đến bộ nhớ và hiệu suất.


2
Đây là một câu trả lời hay, nhưng tôi tưởng tượng có những lúc bạn không muốn xem đệ quy một đối tượng
Jason

16
Có. Theo mặc định nếu bạn không vượt qua true, thì nó sẽ kiểm tra sự bằng nhau tham chiếu nếu giá trị được xem là một đối tượng hoặc mảng. Trong trường hợp đó, bạn nên chỉ định rõ ràng các thuộc tính, như $scope.$watch('form.name')$scope.$watch('form.surname')
rossipedia

3
Cảm ơn. Đó chính xác là những gì tôi đã bỏ lỡ. Jason, bạn nói đúng - bạn không phải lúc nào cũng muốn các đối tượng đệ quy theo dõi, nhưng trong trường hợp của tôi, đó chính xác là những gì tôi cần.
Vladimir Sidorenko

1
Bất biếnJS và so sánh tham chiếu có thể giúp tăng hiệu suất.
Dragos Rusu

13

Đối formtượng không thay đổi, chỉ có nametài sản là

cập nhật fiddle

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

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

12

Chút đỉnh hiệu suất nếu ai đó có một loại kho dữ liệu của dịch vụ với chìa khóa -> cặp giá trị:

Nếu bạn có một dịch vụ gọi là dataStore , bạn có thể cập nhật dấu thời gian bất cứ khi nào đối tượng dữ liệu lớn của bạn thay đổi. Bằng cách này thay vì theo dõi sâu toàn bộ đối tượng, bạn chỉ đang xem dấu thời gian để thay đổi.

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

});

Và trong một chỉ thị, bạn chỉ xem dấu thời gian để thay đổi

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

1
Tôi nghĩ rằng đáng để đề cập rằng trong trường hợp này, bạn sẽ mất chức năng truy cập vào giá trị cũ của dữ liệu bạn đang lưu trữ. newVal, oldValtrong ví dụ này là các giá trị dấu thời gian không phải là giá trị đối tượng quan sát. Nó không làm cho câu trả lời này không hợp lệ, tôi chỉ nghĩ rằng đó là một nhược điểm đáng được đề cập.
Michał Schielmann

Đúng, phương pháp này tôi chủ yếu sử dụng khi tôi muốn tải một cấu trúc dữ liệu phức tạp làm nguồn cho một cái gì đó (ví dụ phiên bản mới của một số dữ liệu). Nếu tôi quan tâm đến các giá trị mới và cũ, tôi sẽ không lưu trữ chúng trong các đối tượng phức tạp lớn, thay vào đó tôi sẽ có một văn bản nhỏ thể hiện điều tôi quan tâm và theo dõi để thay đổi hoặc lấy nó khi dấu thời gian thay đổi.
Ferenc Takacs

5

Lý do tại sao mã của bạn không hoạt động là vì $watchmặc định kiểm tra tham chiếu. Vì vậy, tóm lại, nó đảm bảo rằng đối tượng được truyền cho nó là đối tượng mới. Nhưng trong trường hợp của bạn, bạn chỉ sửa đổi một số thuộc tính của đối tượng biểu mẫu không tạo một thuộc tính mới. Để làm cho nó hoạt động, bạn có thể vượt qua truenhư là tham số thứ ba.

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

Nó sẽ hoạt động nhưng Bạn có thể sử dụng $ watchCollection sẽ hiệu quả hơn $ watch vì $watchCollectionsẽ theo dõi các thuộc tính nông trên đối tượng biểu mẫu. Ví dụ

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

4

Khi bạn đang tìm kiếm thay đổi đối tượng hình thức, cách tiếp cận xem tốt nhất là sử dụng
$watchCollection. Xin vui lòng xem tài liệu chính thức cho các đặc điểm hiệu suất khác nhau.


1

Thử cái này:

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

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

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

0

Đối với bất kỳ ai muốn theo dõi sự thay đổi đối tượng trong một mảng các đối tượng, điều này dường như có hiệu quả đối với tôi (vì các giải pháp khác trên trang này đã không):

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

bạn phải thay đổi trong $ watch ....

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
Trả lời một câu hỏi hai năm tuổi với một câu trả lời đó là một bản sao gần như chính xác của một câu hỏi hiện có? Không mát mẻ.
Jared Smith
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.