Açısal 2'de bir bileşenin yeniden oluşturulmasını nasıl zorlarsınız?


181

Açısal 2'de bir bileşenin yeniden oluşturulmasını nasıl zorlarsınız? Redux ile çalışan hata ayıklama amaçları için, bir bileşeni görünümünü yeniden oluşturmaya zorlamak istiyorum, bu mümkün mü?


"Yeniden oluşturma" ile ne demek istiyorsun. Bağlamalar güncellensin mi?
Günter Zöchbauer

Yeniden oluşturmayı neden zorlamanız gerektiğine dair kısa bir soru mu?
Tuong Le

Yanıtlar:


217

Oluşturma, değişiklik algılandıktan sonra gerçekleşir. Değişiklik algılamayı zorlamak için, değişen bileşen özellik değerleri DOM'ye yayılır (ve ardından tarayıcı bu değişiklikleri görünümde oluşturur), bazı seçenekler şunlardır:

  • ApplicationRef.tick () - Açısal 1'lere benzer $rootScope.$digest()- yani, tüm bileşen ağacını kontrol edin
  • NgZone.run (geri arama) - benzeri$rootScope.$apply(callback) - yani, Açısal 2 bölgesindeki geri arama işlevini değerlendirin. Bence, ama emin değilim, bu geri arama işlevini yürüttükten sonra tam bileşen ağacı kontrol sonuçlanır.
  • ChangeDetectorRef.detectChanges () - benzeri $scope.$digest()- yani, yalnızca bu bileşeni ve alt öğelerini denetleyin

İçe ve sonra enjekte gerekecektir ApplicationRef, NgZoneya ChangeDetectorRefda bileşen içine.

Belirli bir senaryo için, yalnızca tek bir bileşen değişmişse son seçeneği tavsiye ederim.


1
Angular2'nin son sürümü için ChangeDetectorRef üzerinde herhangi bir çalışma kodu var mı? Şimdi, yeni bir kullanıcı oluşturmak için http'nin posta isteğinden sonra görünümün güncellenmediği ve daha sonra yeni nesneyi var olan eski kullanıcı listesine (görünümde yinelemek için kullanılan) iterek başarılı olmadığı bir durumla karşı karşıyayım. Oldukça garip this is the first time I am facing an update not working in ng2. Değişim algılama stratejisi varsayılan ben değişiklik algılama stratejisi ile berbat değil biliyorum.
Gary

1
@Gary, yeni bir soru yayınlamalı ve bileşeninizi ve servis kodunuzu eklemelisiniz (ideal olarak, sorunu gösteren minimal bir dalgıç ekleyin). Gördüğüm yaygın bir sorun thisPOST geri aramasında uygun içeriği kullanmamaktır .
Mark Rajcok

Her değişiklik yaptığımda boruları manuel olarak tetikleyip tetikleyemeyeceğimi biliyor musunuz? Değişiklik algılamayı tetiklemeye çalıştım ama boru güncellenmiyor ... Ayrıca pure:falseboruda da denedim . Çalışıyor ama kullanım durumum için çok pahalı (verimsiz).
ncohen

1
@ncohen, boru güncellemesini manuel olarak tetiklemenin hiçbir yolunun farkında değilim. Bir güncellemeyi tetiklemek istediğinizde saf bir kanal kullanabilir ve nesne referansını değiştirebilirsiniz. Bu, Borular belgesinin "Saf Borular" bölümünde tartışılmıştır . Kullanım durumunuza bağlı olarak, boru yerine bir bileşen özelliği kullanmak isteyebilirsiniz. Bu teknik Borular belgesinin sonunda kısaca tartışılmıştır.
Mark Rajcok

1
@ N-yte, tüm bağlantılar düzeltildi.
Mark Rajcok

47

tx, ihtiyacım olan geçici çözümü buldu:

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

running zone.run bileşeni yeniden oluşturmaya zorlar


6
Bu bağlamda appStore nedir - hangi değişken ve türü? gözlemlenebilir gibi görünüyor ... ama gözlemlenebilirim bir düğmeye tıklayarak yenilemek istediğim bileşenin içinde ... ve üst / geçerli konumdan bir alt bileşen yöntemine / değişkenine nasıl erişileceğini bilmiyorum
Abdeali Chandanwala

28

ChangeDetectorRef yaklaşımı

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

* NgIf kullanarak bileşenimi yeniden yüklemeye zorlarım.

Kabımın içindeki tüm bileşenler, tüm kullanım ömrü kancalarına geri döner.

Şablonda:

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

Sonra ts dosyasında:

public _reload = true;

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

Bunun için teşekkürler, @ loonis! Bunun çalışması gerektiğini hissettim ve dışında her şeyim vardı setTimeout(). Şimdi benimki basit ve hafif bir çözümle çalışıyor!
LHM

Eğer bu 10000+ kez
oy verebilseydim

Dikkat edilmesi gereken 1 şey - yeniden kaybolan ve tekrar görünen kap boyut değişikliklerine neden olabilir ve sayfa titreyebilir
ghosh

9

Buradaki diğer yanıtlar, bileşenin görünümünü (tam yeniden oluşturma ile aynı olmayan) güncelleyecek değişiklik algılama döngülerini tetiklemeye yönelik çözümler sunar.

Tam kullanılarak yapılabilir yok etmek ve bileşen (görünüm tüm yaşam döngüsü kanca arama ve yeniden inşa) yeniden başlatmak hangi yeniden işlemek ng-template, ng-containerve ViewContainerRefşu şekilde:

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

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

Sonra bileşeninde hem referansı olan #outletve #contentbiz iki girişteki içeriği temizleyebilir ve çocuk bileşeninin başka örneğini ekleyebilirsiniz:

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

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

Ek olarak, ilk içerik AfterContentInitkancaya eklenmelidir :

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

Tam çalışma çözümüne https://stackblitz.com/edit/angular-component-rerender adresinden ulaşabilirsiniz.


1

ChangeDetectorRef.detectChanges() genellikle bunu yapmanın en odaklanmış yoludur. ApplicationRef.tick()genellikle bir balyoz yaklaşımıdır.

Kullanmak ChangeDetectorRef.detectChanges()için bileşeninizin üstünde buna ihtiyacınız olacak:

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

... o zaman, genellikle yapıcıya böyle enjekte ettiğinizde takma adınız vardır:

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

Sonra, uygun yerde , şöyle deyin:

this.cdr.detectChanges();

Nerede aramak ChangeDetectorRef.detectChanges()son derece önemli olabilir. Buna gerek tamamen yaşam döngüsünü anlamak ve tam olarak uygulama işleyen ve bileşenlerini render nasıl. Burada ödevinizi tamamen yapmak ve Açısal yaşam döngüsünü içeriden anladığınızdan emin olmak için bir yedek yoktur. Sonra, bunu anladıktan sonra, ChangeDetectorRef.detectChanges()uygun şekilde kullanabilirsiniz (bazen nerede kullanmanız gerektiğini anlamak çok kolaydır, diğer zamanlarda çok karmaşık olabilir).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.