如何手动重新渲染Angular 5组件

33

有没有一种方法可以手动重新渲染组件,例如当用户点击按钮时?

我看过类似的帖子,但这些方法对我都不起作用,例如这里

例如,

renderComponent() {
   // force component re-render
}

1
你尝试使用 ChangeDetectorRef.detectChanges() 了吗? - candidJ
9个回答

22

如果您想操作视图(添加、移除或重新附加),这里是一个示例:

import { Component, ViewContainerRef, AfterViewInit, ViewChild, ViewRef,TemplateRef} from '@angular/core';

import { ChildComponent } from './child.component';

@Component({
  selector: 'host-comp',
  template: `
    <h1>I am a host component</h1>

    <ng-container #vc><ng-container>

    <br>

    <button (click)="insertChildView()">Insert Child View</button>
    <button (click)="removeChildView()">Remove Child View</button>
    <button (click)="reloadChildView()">Reload Child View</button>

    <ng-template #tpl>
      <child-comp><child-comp>
    <ng-template>

  `
})
export class HostComponent implements AfterViewInit{

  @ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef;

  @ViewChild('tpl', {read: TemplateRef}) tpl: TemplateRef<any>;

  childViewRef: ViewRef;

  constructor(){}

  ngAfterViewInit(){
    this.childViewRef = this.tpl.createEmbeddedView(null);
  }

  insertChildView(){
    this.vc.insert(this.childViewRef);
  }

  removeChildView(){
    this.vc.detach();
  }

  reloadChildView(){
    this.removeChildView();
    setTimeout(() =>{
      this.insertChildView();
    }, 3000);
  }
}

这里有一个实时的示例


5
超时是仅用于可见感知还是对于异步操作是“必要”的? - Daniel

12

如果我理解你的问题正确,你在问关于ChangeDetectionStrategy,Angular有两个选项

enum ChangeDetectionStrategy {
  OnPush: 0
  Default: 1
}

如果您使用默认设置,它将在每次事件(如单击)后"重新渲染"您的视图。

如果您使用OnPush,它将在使用带有| async的observable时重新渲染,或者您可以注入ChangeDetectorRef并“请求”重新渲染。

constructor(private ref: ChangeDetectorRef) {
    setInterval(() => {
      this.numberOfTicks++;
      // the following is required, otherwise the view will not be updated
      this.ref.markForCheck();
    }, 1000);
  }

但是,只有当你运行在 Angular 内部时,这才是真实的。有时,如果你正在监听外部服务并且运行在 NgZone 之外,你需要执行 ngZone.run

this._ngZone.run(() => { console.log('Do change detection here'); });

它不起作用,onInit中的console.log没有记录任何内容。 - Eugen Bogdanovich
@EugenBogdanovich 如果您有其他问题,请发布不带代码的问题。我不知道如何帮助。 - Vova Bilyachat
ChangeDetectorRef并不会真正重新渲染,它只是使用digest循环更新数据绑定。 - Eugen Bogdanovich
@EugenBogdanovich 我明白你的意思了,问题已经被编辑过了,而我的回答是针对原始问题的。所以你说得对,变更检测不会重新渲染或重新创建组件,它只会更新视图。 - Vova Bilyachat

9
你可以使用 detectChanges() 或者 markForCheck() 来通知 Angular 再次渲染组件。

4
ChangeDetectorRef并不会真正重新渲染,它只是使用脏检查周期更新数据绑定。 - Tomas Katz

9
我已经为此重新渲染的目的创建了一个指令。

/**
 * Example:
 *
 * <ng-container *rerender='changingInput'>
 *    this content will be re-rendered everytime `changingInput` changes
 * </ng-container>
 */

import { Directive,
         Input,
         TemplateRef,
         ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[rerender]'
})
export class RerenderDirective {
  constructor(
    private templateRef:    TemplateRef<any>,
    private viewContainer:  ViewContainerRef
  ) {}

  // if detects changes of the input `val`, clear and rerender the view
  @Input() set rerender(val) {
    this.viewContainer.clear();
    this.viewContainer.createEmbeddedView(this.templateRef);
  }
}

请查看我的 Gist 获取最新更新。


1
谢谢 - 我已经寻找这样的东西1年了! 调用ChangeDetectorRef方法不起作用。 - Deian

6
HTML
<app-component1 *ngIf="FLAG"></app-component1>

TS

  constructor(private changeDetectorRef: ChangeDetectorRef) {
      this.FLAG = true
  }

  renderComponent() {
      this.FLAG = false;
      this.changeDetectorRef.detectChanges();
      this.FLAG = true;
  }

1
拙劣但有效 - Dainius Lukša
太棒了!✌ - undefined

3

您可以通过临时覆盖路由重用策略来欺骗路由器渲染当前组件的最新副本.. 在其他一些SO答案中发现 :)
在ngOnInit中:

this.router.routeReuseStrategy.shouldReuseRoute = () => false;

1
你可以使用这个 Angular 库 ngx-rerender https://www.npmjs.com/package/ngx-rerender
<stuff-to-rerender *mcRerender="trigger">Some Content</stuff-to-rerender>

class MyComponent {
  public trigger: number = 0;

  public rerender(): void {
    this.trigger++;
  }
}

无论何时调用rerender函数,您的组件都将被完全重新渲染。

1

我尝试了这个帖子中的答案,但是我不得不进行修改才能使其工作。让我分享我的可行代码。

.html-----------------

<button (click)="addChild()">ADD</button>
<button (click)="removeChild()">REMOVE</button>

<ng-container #vc></ng-container>
<ng-template #tpl>
   <child-component id ="child-modal"></child-component>
</ng-template>

.ts---------------------
import { Component, ViewChild, ViewContainerRef, TemplateRef, ViewRef } from '@angular/core';

export class ParentComponent{

@ViewChild('vc', { read: ViewContainerRef }) vc: ViewContainerRef;
@ViewChild('tpl', { read: TemplateRef }) tpl: TemplateRef<any>;

addChild(){
let view = this.tpl.createEmbeddedView(null);
this.vc.insert(view);
}

removeChild(){
 this.vc.clear();
}

这个页面很有帮助。确保在addchild()中添加let view = this.tpl.createEmbeddedView(null);


-1
也许可以使用 window.location.reload()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接