【问题标题】:How to re-render a component manually Angular 5如何手动重新渲染组件Angular 5
【发布时间】:2018-10-27 05:22:03
【问题描述】:

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

我看过类似的帖子,但没有一个对我有用,例如 here

例如,

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

【问题讨论】:

  • 您尝试使用ChangeDetectorRef.detectChanges() 吗?

标签: angular typescript


【解决方案1】:

如果您打算操作视图(添加、删除或重新附加),那么这里是一个示例:

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);
  }
}

live example here

【讨论】:

  • 超时只是为了明显可见,还是异步“必要”?
【解决方案2】:

如果我理解正确,您是在询问 ChangeDetectionStrategy Angular 有两个options

enum ChangeDetectionStrategy {
  OnPush: 0
  Default: 1
}

如果您使用默认值,它只会在每次点击等事件后“重新渲染”您查看的内容。

如果你使用 OnPush,如果你使用 observable 和 | 它会重新渲染。 async 或者您可以注入 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'); });

【讨论】:

  • 它不起作用,console.log in onInit 没有记录任何东西
  • @EugenBogdanovich 如果您有其他问题,它会按预期工作,在没有代码的情况下发布您的问题我不知道如何提供帮助\
  • 来自另一条评论:ChangeDetectorRef 并没有真正重新渲染它只是使用摘要周期更新数据绑定
  • @EugenBogdanovich 我明白了你的意思,问题已被编辑,我的回答是针对原始问题。所以是的,你是对的,更改检测不会重新渲染或重新创建组件,它只会更新视图。
【解决方案3】:

您可以使用detectChanges()markForCheck() 告诉 Angular 重新渲染组件。

【讨论】:

  • ChangeDetectorRef 并没有真正重新渲染它只是使用摘要循环更新数据绑定
【解决方案4】:

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

/**
 * 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 年了!调用 ChangeDetectorRef 方法不起作用
【解决方案5】:

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

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

【讨论】:

    【解决方案6】:

    我尝试了此线程中的答案,但我必须进行修改才能使其正常工作。让我分享我的工作代码。

    .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();
    }
    

    This page 很有帮助。确保在addchild() 中添加let view = this.tpl.createEmbeddedView(null);

    【讨论】:

      猜你喜欢
      • 2016-12-14
      • 2020-09-19
      • 2021-04-04
      • 2022-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-27
      相关资源
      最近更新 更多