Phát hiện thay đổi kích hoạt bằng tay trong Angular


387

Tôi đang viết một thành phần Angular có một tài sản Mode(): string.

Tôi muốn có thể đặt thuộc tính này theo chương trình không đáp ứng với bất kỳ sự kiện nào.

Vấn đề là trong trường hợp không có sự kiện trình duyệt, ràng buộc mẫu {{Mode}}không cập nhật.

Có cách nào để kích hoạt phát hiện thay đổi này bằng tay không?

Câu trả lời:


640

Hãy thử một trong những điều sau:

  • ApplicationRef.tick()- tương tự như AngularJS $rootScope.$digest()- tức là kiểm tra cây thành phần đầy đủ
  • NgZone.run(callback)- tương tự như $rootScope.$apply(callback)- tức là, đánh giá chức năng gọi lại bên trong Vùng góc. Tôi nghĩ, nhưng tôi không chắc chắn, điều này cuối cùng sẽ kiểm tra cây thành phần đầy đủ sau khi thực hiện chức năng gọi lại.
  • ChangeDetectorRef.detectChanges()- tương tự như $scope.$digest()- tức là chỉ kiểm tra thành phần này và con của nó

Bạn có thể tiêm ApplicationRef, NgZonehoặc ChangeDetectorRefvào thành phần của bạn.


1
Cảm ơn, tôi đã chọn giải pháp thứ 3 để không kiểm tra mọi thứ, vì các thay đổi khá cục bộ. Tôi nên điều tra các lựa chọn khác khi tôi có nhiều thời gian hơn. Có bất kỳ ý nghĩa hiệu suất với mỗi lựa chọn?
jz87

36
+1 cho ChangeDetectorRef.detectChanges(). trình xác nhận đã được kích hoạt trước khi chỉ thị của tôi có thể cập nhật giá trị của đầu vào.
ps2goat

7
ApplicationRef.tick () và ChangeDetectorRef.detectChanges () vẫn có mặt trong bản 2.0.0 cuối cùng.
Max Mumford

51
Chỉ cần nghĩ rằng tôi sẽ đề cập đến điều này. Đây không phải là phương thức tĩnh, chúng là phương thức cá thể. Bạn sẽ cần phải tiêm các lớp này như các dịch vụ.
Stephen Paul

1
ApplicationRef.tick () đã giúp giải quyết vấn đề với FireFox v17 (<20)
Dan J

123

Tôi đã sử dụng tài liệu tham khảo câu trả lời được chấp nhận và muốn đưa ra một ví dụ, vì tài liệu Angular 2 rất khó đọc, tôi hy vọng điều này dễ dàng hơn:

  1. Nhập khẩu NgZone:

    import { Component, NgZone } from '@angular/core';
    
  2. Thêm nó vào trình xây dựng lớp của bạn

    constructor(public zone: NgZone, ...args){}
    
  3. Chạy mã với zone.run:

    this.zone.run(() => this.donations = donations)
    

6
bạn nên đặt zone.runmã ở đâu và chính xác là donationsgì?
suku

Đóng góp @suku là bất kỳ tài sản nào bạn muốn cập nhật, vì vậy nó có thể là this.foo = bar. area.run đi bất cứ nơi nào bạn muốn cập nhật công cụ.
Matthew tùy chọn Meehan

4
Tôi đã sử dụng giải pháp này để buộc cập nhật chế độ xem khi sử dụng document.addEventListener ("tiếp tục", gọi lại)
marcovtwout

71

Tôi đã có thể cập nhật nó với markForCheck ()

Nhập ChangeDetectorRef

import { ChangeDetectorRef } from '@angular/core';

Tiêm và khởi tạo nó

constructor(private ref: ChangeDetectorRef) { 
}

Cuối cùng đánh dấu phát hiện thay đổi sẽ diễn ra

this.ref.markForCheck();

Đây là một ví dụ nơi markForCheck () hoạt động và DetChanges () không.

https://plnkr.co/edit/RfJwHqEVJcMU9ku9XNE7?p=preview

EDIT: Ví dụ này không mô tả vấn đề nữa :( Tôi tin rằng nó có thể đang chạy phiên bản Angular mới hơn, nơi nó đã được sửa.

(Nhấn STOP / RUN để chạy lại)


Điểm Goo cho DetChanges () không hoạt động. Tôi đã nhận thấy vấn đề tương tự và thấy rằng nó hoạt động nếu phát hiện thay đổi không có OnPush. Sẽ là tốt để có được một lời giải thích cho điều đó ...
Christian

2
Có vẻ như DetChanges thực sự đang làm việc trong plunker này? Tui bỏ lỡ điều gì vậy?
Jared_C

1
Bạn nên lưu ý rằng ChangeDetectorRef chỉ hoạt động trong Thành phần
kevinius

(!) Đây là một ví dụ tồi tệ, tôi xin lỗi. Ví dụ không hiển thị bất cứ điều gì. Mục đầu tiên chỉ được ghi đè. Chỉ cần điều chỉnh bộ hẹn giờ một chút ...
Peter Stegnar

Ví dụ này không khắc phục được vấn đề nữa :( Tôi tin rằng nó có thể đang chạy phiên bản Angular mới hơn khi đã sửa.
Nuno Tomas

7

Trong Angular 2+, hãy thử trang trí @Input

Nó cho phép một số ràng buộc tài sản tốt đẹp giữa các thành phần cha mẹ và con.

Đầu tiên tạo một biến toàn cục trong cha mẹ để giữ đối tượng / thuộc tính sẽ được truyền cho con.

Tiếp theo tạo một biến toàn cục trong con để giữ đối tượng / thuộc tính được truyền từ cha mẹ.

Sau đó, trong html cha, nơi sử dụng mẫu con, thêm ký hiệu ngoặc vuông với tên của biến con, sau đó đặt nó bằng với tên của biến cha. Thí dụ:

<child-component-template [childVariable] = parentVariable>
</child-component-template>

Cuối cùng, nơi thuộc tính con được xác định trong thành phần con, hãy thêm Trình trang trí đầu vào:

@Input()
public childVariable: any

Khi biến cha mẹ của bạn được cập nhật, nó sẽ chuyển các bản cập nhật cho thành phần con, nó sẽ cập nhật html của nó.

Ngoài ra, để kích hoạt một chức năng trong thành phần con, hãy xem ngOnChanges.


2
KHÔNG ... đó là vấn đề ... nếu bạn cập nhật trong cha mẹ ... giả sử exmaple được cập nhật "bằng cách tham chiếu" trong một phương thức tĩnh, đứa trẻ sẽ không nhận nó vì phát hiện thay đổi đã không xảy ra
Bhail

Tôi đã có cùng một vấn đề trong nhiều ngày nay. Tôi cố gắng lấy dữ liệu từ phụ trợ PHP và dữ liệu hoàn toàn không cập nhật. Trên Microsoft Edge hoạt động tốt nhưng trên trình duyệt khác thì không. Tôi tiếp tục nhận được dữ liệu lần đầu tiên tôi bắt đầu nhưng nếu dữ liệu thay đổi thì nó không được cập nhật khi xem
el6976

1

ChangeDetectorRef.detectChanges () - tương tự $ scope. $ Digest () - tức là chỉ kiểm tra thành phần này và các phần tử con của nó

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.