2016-04-01 13 views
9

Tôi thực sự hài lòng với phương thức $ onChanges "mới" mà bạn có thể thực hiện trong bộ điều khiển của một thành phần. Tuy nhiên nó dường như chỉ được kích hoạt khi biến bị ràng buộc bị ghi đè từ bên ngoài thành phần của tôi, không (ví dụ) khi một mục được thêm vào một mảng hiện có

Hành vi hoặc lỗi này có ý định? Có cách nào khác để nghe các bản cập nhật cho các ràng buộc đầu vào của tôi, ngoài việc thực hiện một phạm vi $. $ Xem trên nó?

Tôi đang sử dụng góc 1.5.3

Trả lời

16

Trước TL; DR Đối với một mảng giáp qua một chiều ràng buộc, một biểu hiện chiếc đồng hồ được thêm vào mà không kiểm tra xem có sự bình đẳng đối tượng nhưng sử dụng tài liệu tham khảo kiểm tra. Điều này có nghĩa là việc thêm một phần tử vào mảng sẽ không bao giờ kích hoạt phương thức '$ onChanges', vì trình theo dõi sẽ không bao giờ bị 'bẩn'.

Tôi đã tạo một plnkr đó chứng tỏ điều này: http://plnkr.co/edit/25pdLE?p=preview

Nhấp vào 'thêm rau ở ngoài' và 'mảng tham chiếu thay đổi bên ngoài và nhìn vào 'Số $ onChanges gọi'. Nó sẽ chỉ thay đổi với nút thứ hai.

Giải thích đầy đủ Để nắm bắt đầy đủ những gì đang diễn ra, chúng ta nên kiểm tra cơ sở mã góc. Khi tìm thấy ràng buộc '<', mã sau được sử dụng để thiết lập biểu thức xem.

case '<': 
     if (!hasOwnProperty.call(attrs, attrName)) { 
      if (optional) break; 
      attrs[attrName] = void 0; 
     } 
     if (optional && !attrs[attrName]) break; 

     parentGet = $parse(attrs[attrName]); 

     destination[scopeName] = parentGet(scope); 
// IMPORTANT PART // 
     removeWatch = scope.$watch(parentGet, function  parentValueWatchAction(newParentValue) { 
      var oldValue = destination[scopeName]; 
      recordChanges(scopeName, newParentValue, oldValue); 
      destination[scopeName] = newParentValue; 
     }, parentGet.literal); 
// ------------- // 
     removeWatchCollection.push(removeWatch); 
     break; 

Phần quan trọng ở đây là cách biểu thức 'phạm vi. $ Watch' được thiết lập. Các tham số duy nhất được truyền là biểu thức được phân tích cú pháp và hàm listener. Hàm listener được kích hoạt khi '$ watch' được tìm thấy trong chu kỳ digest. Nếu nó được kích hoạt, người nghe sẽ thực thi phương thức 'recordChanges'. Điều này ghi lại một nhiệm vụ gọi lại '$ onChanges' sẽ được thực thi trong giai đoạn '$ postDigest' và thông báo cho tất cả các thành phần đang lắng nghe móc vòng đời '$ onChanges' để cho họ biết nếu giá trị đã thay đổi.

Điều quan trọng cần ghi nhớ ở đây, nếu '$ watcher' không bao giờ bị bẩn, cuộc gọi lại '$ onChanges' không được kích hoạt. Nhưng quan trọng hơn, bằng cách biểu thức '$ watch' được tạo ra, nó sẽ KHÔNG BAO GIỜ bị bẩn, KHÔNG BAO GIỜ thay đổi tham chiếu. Nếu bạn muốn kiểm tra sự bình đẳng giữa các đối tượng thay vì tham khảo, bạn phải vượt qua một tham số thứ ba thêm rằng yêu cầu này:

$watch: function(watchExp, listener, objectEquality, prettyPrintExpression) 

Vì đây không phải là trường hợp ở đây với con đường một cách ràng buộc được thiết lập, nó sẽ luôn luôn kiểm tra để tham khảo.

Điều này có nghĩa, nếu bạn thêm phần tử vào mảng, tham chiếu sẽ không bị thay đổi. Có nghĩa là '$ watcher' sẽ không bao giờ bị bẩn, nghĩa là phương thức '$ onChanges' sẽ không được gọi để thay đổi mảng.

Để chứng minh điều này, tôi đã tạo ra một plnkr: http://plnkr.co/edit/25pdLE?p=preview

Nó chứa hai thành phần, bên ngoài và bên trong. Bên ngoài có giá trị chuỗi nguyên thủy có thể được thay đổi thông qua một hộp đầu vào và một mảng có thể được mở rộng bằng cách thêm một phần tử hoặc có tham chiếu của nó thay đổi.
Bên trong có hai biến giới hạn một chiều, giá trị và mảng. Nó lắng nghe tất cả các thay đổi.

this.$onChanges = setType; 
function setType() { 
    console.log("called"); 
    vm.callCounter++; 
} 

Nếu bạn nhập vào trường nhập, cuộc gọi lại '$ onChanges' sẽ được kích hoạt mỗi lần. Điều này là hợp lý và được mong đợi, vì một chuỗi là nguyên thủy nên nó không thể được so sánh bằng tham chiếu, có nghĩa là '$ watcher' sẽ bị bẩn, và móc vòng đời '$ onChanges' bị bắn.

Nếu bạn nhấp vào 'Thêm rau ở ngoài, nó sẽ thực thi đoạn mã sau:

this.changeValueArray = function() { 
     vm.valueArray.push("tomato"); 
    }; 

Ở đây chúng ta chỉ cần thêm một giá trị cho mảng bị chặn hiện có. Chúng tôi đang làm việc bằng cách tham chiếu ở đây, do đó, '$ watcher' không được kích hoạt và không có gọi lại. Bạn sẽ không thấy tăng truy cập hoặc câu lệnh 'được gọi' trong bảng điều khiển của mình.

Lưu ý: Nếu bạn bấm vào 'Thêm thứ gì đó vào mảng' bên trong thành phần bên trong, mảng trong thành phần bên ngoài cũng thay đổi. Điều này là hợp lý, vì chúng tôi đang cập nhật cùng một mảng chính xác theo tham chiếu. Vì vậy, mặc dù nó là một ràng buộc một chiều, mảng có thể được cập nhật từ bên trong thành phần bên trong.

Nếu bạn thay đổi tham chiếu trong thành phần bên ngoài bằng cách nhấp vào 'Thay đổi tham chiếu mảng ở bên ngoài', gọi lại '$ onChanges' được kích hoạt như mong đợi.

Để trả lời câu hỏi của bạn: Hành vi này có phải là hành vi hoặc lỗi không? Tôi đoán đây là hành vi dự định. Nếu không, họ sẽ cho bạn tùy chọn để xác định ràng buộc '<' của bạn theo cách nó sẽ kiểm tra sự bình đẳng đối tượng. Bạn luôn có thể tạo một vấn đề về github và chỉ cần đặt câu hỏi nếu bạn muốn.

+0

cảm ơn, tôi sẽ tạo sự cố trên GitHub – jordydejong

+0

Bạn chắc chắn có thể tham khảo bài đăng của tôi tại đây. Hoặc sử dụng plnkr của tôi. – KwintenP

+0

được tạo: https://github.com/angular/angular.js/issues/14378 – jordydejong

Các vấn đề liên quan