2013-03-12 34 views
52

Tôi đang cố gắng tìm ra lý do tại sao $watch của tôi không được kích hoạt. Đây là một đoạn trích từ bộ điều khiển có liên quan:

$scope.$watch('tasks', function (newValue, oldValue) { 
    //do some stuff 
    //only enters here once 
    //newValue and oldValue are equal at that point 
}); 

$scope.tasks = tasksService.tasks(); 

$scope.addTask = function (taskCreationString) { 
    tasksService.addTask(taskCreationString);//modifies tasks array 
}; 

Theo quan điểm của tôi, tasks được rõ ràng đang được cập nhật một cách chính xác như tôi đã chiều dài của nó bị ràng buộc như vậy:

<span>There are {{tasks.length}} total tasks</span> 

tôi đang thiếu gì?

+0

Nó có vẻ như vấn đề này cũng áp dụng cho quan sát đối tượng. Thay vào đó, bạn phải xem một thuộc tính cụ thể. – VSO

Trả lời

131

Hãy thử $watch('tasks.length', ...) hoặc $watch('tasks', function(...) { ... }, true).

Theo mặc định, $watch không kiểm tra đối tượng bình đẳng, nhưng chỉ để tham khảo. Vì vậy, $watch('tasks', ...) sẽ luôn đơn giản trả về cùng một tham chiếu mảng, không thay đổi.

Cập nhật: v1.1.4 Góc cho biết thêm một phương pháp $watchCollection() để xử lý trường hợp này:

Shallow đồng hồ các thuộc tính của một đối tượng và cháy bất cứ khi nào bất kỳ thuộc tính thay đổi (đối với mảng này ngụ ý theo dõi mảng các mục, đối với các bản đồ đối tượng, điều này ngụ ý xem các thuộc tính). Nếu phát hiện thay đổi, cuộc gọi lại listener bị kích hoạt.

+0

cảm ơn vì lời giải thích, tôi đã dành hàng giờ không biết điều này – asumaran

+3

Điều này làm giảm bớt nỗi đau và nỗi buồn, cảm ơn! –

+0

cảm ơn. đã giúp tôi hôm nay – VeteranLK

13

Câu trả lời rất hay bởi @Mark. Ngoài câu trả lời của mình, có một chức năng quan trọng của hàm $watch mà bạn cần biết.

Với việc kê khai $watch chức năng như sau:

$watch(watch_expression, listener, objectEquality) 

Các $watchnghe hàm được gọi chỉ khi giá trị cường độ dòng điện đồng hồ biểu (trong trường hợp của bạn nó là 'tasks') và các cuộc gọi trước đến biểu thức đồng hồ không bằng nhau. Góc giúp tiết kiệm giá trị của đối tượng để so sánh sau này. Do đó, việc xem các tùy chọn phức tạp sẽ có những tác động bất lợi và bộ nhớ. Về cơ bản, biểu thức xem đơn giản hơn giá trị càng tốt.

+5

+1. Tôi sẽ đề cập đến (để hoàn thành) rằng chức năng nghe cũng được gọi một lần ban đầu để khởi tạo trình theo dõi. Điều này cần xảy ra _even nếu 'watch_expression' không thay đổi_. –

+0

yeah ... đã sao chép tài liệu. https://docs.angularjs.org/api/ng/type/$rootScope.Scope – hupseb

5

Tôi muốn giới thiệu cố gắng

$scope.$watch('tasks | json', ...) 

Đó sẽ bắt tất cả các thay đổi đối với mảng tasks, vì nó so sánh mảng serialized như là một chuỗi.

+3

Như một lưu ý cảnh báo, giải pháp này sẽ liên quan đến việc tuần tự hóa JSON trên mỗi chu kỳ tiêu hóa, không tuyệt vời cho hiệu suất (đặc biệt nếu đối tượng là phức tạp một, hoặc một mảng dài). Nó * sẽ * làm việc, nhưng nó là một chút của một 'sledgehammer để crack một nut'. – decates

+0

kiểm tra hiệu suất nhỏ cho các kích thước đối tượng khác nhau sẽ là thú vị. – abimelex

+0

Điều này đặt tôi trên con đường đúng để sửa chữa cùng một vấn đề với các đối tượng. – VSO

2

Đối với một mảng chiều bạn có thể sử dụng $watchCollection

$scope.names = ['igor', 'matias', 'misko', 'james']; 
$scope.dataCount = 4; 

$scope.$watchCollection('names', function(newNames, oldNames) { 
    $scope.dataCount = newNames.length; 
}); 
Các vấn đề liên quan