Làm cách nào để buộc kết xuất lại thành phần trong Angular 2?


181

Làm cách nào để buộc kết xuất lại thành phần trong Angular 2? Đối với các mục đích gỡ lỗi làm việc với Redux, tôi muốn buộc một thành phần hiển thị lại chế độ xem của nó, điều đó có thể không?


Bạn có ý nghĩa gì khi "tái hiện". Cập nhật các ràng buộc?
Günter Zöchbauer

Chỉ là một câu hỏi nhanh tại sao bạn cần buộc kết xuất lại?
Tường Lê

Câu trả lời:


217

Kết xuất xảy ra sau khi phát hiện thay đổi. Để buộc phát hiện thay đổi, để các giá trị thuộc tính thành phần đã thay đổi được truyền đến DOM (và sau đó trình duyệt sẽ hiển thị những thay đổi đó trong chế độ xem), đây là một số tùy chọn:

  • ApplicationRef.tick () - tương tự như Angular 1's $rootScope.$digest()- nghĩa là kiểm tra cây thành phần đầy đủ
  • NgZone.run (gọi lại) - 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 Angular 2. 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à các phần tử con của nó

Bạn sẽ cần phải nhập khẩu và sau đó bơm ApplicationRef, NgZonehoặc ChangeDetectorRefvào thành phần của bạn.

Đối với kịch bản cụ thể của bạn, tôi sẽ đề xuất tùy chọn cuối cùng nếu chỉ một thành phần duy nhất đã thay đổi.


1
Bất kỳ mã làm việc nào trên ChangeDetectorRef cho phiên bản cuối cùng của angular2? Bây giờ tôi đang phải đối mặt với tình huống chế độ xem không được cập nhật sau khi yêu cầu bài đăng của http để tạo người dùng mới và sau đó thành công đẩy đối tượng mới vào danh sách người dùng cũ hiện có (được sử dụng để lặp lại trong chế độ xem). Khá lạ mà this is the first time I am facing an update not working in ng2. Chiến lược phát hiện thay đổi là mặc định vì vậy tôi biết rằng tôi đã không nhầm lẫn với chiến lược phát hiện thay đổi.
Gary

1
@Gary, bạn nên đăng một câu hỏi mới và bao gồm thành phần và mã dịch vụ của bạn (lý tưởng nhất là bao gồm một trình bày tối thiểu thể hiện vấn đề). Một vấn đề phổ biến tôi đã thấy là không sử dụng thisbối cảnh thích hợp trong cuộc gọi lại POST.
Mark Rajcok

Bạn có biết nếu tôi có thể tự kích hoạt các đường ống bất cứ khi nào tôi thực hiện thay đổi không? Tôi đã cố gắng kích hoạt phát hiện thay đổi nhưng đường ống không cập nhật ... Tôi cũng đã thử với pure:falseđường ống. Nó hoạt động nhưng nó quá đắt (không hiệu quả) cho trường hợp sử dụng của tôi.
ncohen

1
@ncohen, tôi không biết cách nào để tự kích hoạt cập nhật đường ống. Bạn có thể sử dụng một đường ống thuần túy và thay đổi tham chiếu đối tượng bất cứ khi nào bạn muốn kích hoạt cập nhật. Điều này được thảo luận trong phần "Pure Faucet" trong tài liệu ống . Tùy thuộc vào trường hợp sử dụng của bạn, bạn có thể muốn sử dụng thuộc tính thành phần thay vì đường ống. Kỹ thuật này được thảo luận ngắn gọn ở phần cuối của tài liệu ống.
Mark Rajcok

1
@ N-ate, tất cả các liên kết đã được sửa.
Mark Rajcok

47

tx, tìm thấy cách giải quyết tôi cần:

  constructor(private zone:NgZone) {
    // enable to for time travel
    this.appStore.subscribe((state) => {
        this.zone.run(() => {
            console.log('enabled time travel');
        });
    });

đang chạy area.run sẽ buộc thành phần kết xuất lại


6
appStore là gì trong bối cảnh này - loại biến và loại của nó là gì? dường như có thể quan sát được ... nhưng tôi có thể quan sát được bên trong thành phần mà tôi muốn làm mới chỉ bằng một nút bấm ... và tôi không biết cách truy cập một phương thức / biến thành phần con từ vị trí hiện tại / cha mẹ
Abdeali Chandanwala

28

Cách tiếp cận ChangeDetectorRef

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';

export class MyComponent {

    constructor(private cdr: ChangeDetectorRef) { }

    selected(item: any) {
        if (item == 'Department')
            this.isDepartment = true;
        else
            this.isDepartment = false;
        this.cdr.detectChanges();
    }

}

14

Tôi buộc tải lại thành phần của mình bằng cách sử dụng * ng If.

Tất cả các thành phần bên trong container của tôi quay trở lại các móc vòng đời đầy đủ.

Trong mẫu:

<ng-container *ngIf="_reload">
    components here 
</ng-container>

Sau đó trong tệp ts:

public _reload = true;

private reload() {
    setTimeout(() => this._reload = false);
    setTimeout(() => this._reload = true);
}

Cảm ơn vì điều này, @loonis! Tôi cảm thấy như thế này nên hoạt động, và tôi đã có mọi thứ trừ setTimeout(). Bây giờ tôi đang làm việc với một giải pháp đơn giản và nhẹ!
LHM

nếu tôi có thể nâng cấp hơn 10000 lần này ..
Yazan Khalaileh

1 điều cần lưu ý - container biến mất và xuất hiện lại có thể gây ra thay đổi kích thước và trang có thể nhấp nháy
ghosh

9

Các câu trả lời khác ở đây cung cấp các giải pháp để kích hoạt các chu kỳ phát hiện thay đổi sẽ cập nhật chế độ xem của thành phần (không giống như kết xuất lại hoàn toàn).

Full tái render, đó sẽ phá hủy và khởi tạo lại thành phần (gọi tất cả các lưỡi câu vòng đời và xây dựng lại quan điểm) có thể được thực hiện bằng cách sử dụng ng-template, ng-containerViewContainerReftheo cách sau đây:

<div>
  <ng-container #outlet >
  </ng-container>
</div>

<ng-template #content>
  <child></child>
</ng-template>

Sau đó, trong thành phần có tham chiếu đến cả hai #outlet#contentchúng ta có thể xóa nội dung của các cửa hàng và chèn một phiên bản khác của thành phần con:

@ViewChild("outlet", {read: ViewContainerRef}) outletRef: ViewContainerRef;
@ViewChild("content", {read: TemplateRef}) contentRef: TemplateRef<any>;

private rerender() {
    this.outletRef.clear();
    this.outletRef.createEmbeddedView(this.contentRef);
}

Ngoài ra, nội dung ban đầu nên được chèn vào AfterContentInithook:

ngAfterContentInit() {
    this.outletRef.createEmbeddedView(this.contentRef);
}

Giải pháp làm việc đầy đủ có thể được tìm thấy ở đây https://stackblitz.com/edit/angular-component-rerender .


1

ChangeDetectorRef.detectChanges()thường là cách tập trung nhất để làm điều này. ApplicationRef.tick()thường là quá nhiều của một cách tiếp cận búa tạ.

Để sử dụng ChangeDetectorRef.detectChanges(), bạn sẽ cần thứ này ở đầu thành phần của bạn:

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

... sau đó, thông thường bạn sẽ bí danh rằng khi bạn tiêm nó vào hàm tạo của bạn như thế này:

constructor( private cdr: ChangeDetectorRef ) { ... }

Sau đó, ở nơi thích hợp , bạn gọi nó như thế này:

this.cdr.detectChanges();

Nơi bạn gọi ChangeDetectorRef.detectChanges()có thể rất có ý nghĩa. Bạn cần hiểu hoàn toàn vòng đời và chính xác cách ứng dụng của bạn hoạt động và hiển thị các thành phần của nó. Không có sự thay thế nào ở đây để hoàn thành bài tập về nhà của bạn và đảm bảo bạn hiểu được vòng đời Angular từ trong ra ngoài. Sau đó, khi bạn hiểu điều đó, bạn có thể sử dụng ChangeDetectorRef.detectChanges()một cách thích hợp (đôi khi rất dễ hiểu bạn nên sử dụng nó ở đâu, những lần khác có thể rất phức tạp).

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.