【问题标题】:How do I re-render a component manually?如何手动重新渲染组件?
【发布时间】:2016-12-14 16:04:05
【问题描述】:

我是 Angular2 的新手,我已经习惯了 Angular 1 的摘要循环,这意味着如果我更新视图的范围,我可以通过调用 $scope.$digest() 手动触发摘要。但是,我不确定如何在 Angular2 中执行此操作,尤其是考虑到新框架没有旧版本所具有的隐式数据绑定。

这是我的问题。我有一个路由,当一个带有参数的 url 被点击时加载一个组件:

// Router
export const AppRoutes : RouterConfig = [
    {
    path: 'my/:arg/view',
    component: MyComponent  
    }
]

然后我有这个组件:

// Component
export class MyComponent {
    constructor(private route : ActivatedRoute,
      private r : Router) {
    let id = parseInt(this.route.params['value'].id);
    console.log(id);
    // do stuff with id
    }

    reloadWithNewId(id:number) {
        this.r.navigateByUrl('my/' + id + '/view');
    }
}

假设我导航到 url /my/1/view。它将调用构造函数并记录数字1。但是,如果我使用新的 id reloadWithNewIf(2) 调用 reloadWithNewId,则不会再次调用构造函数。如何手动重新加载组件?

【问题讨论】:

标签: angular angular2-routing


【解决方案1】:

应该不需要重新加载组件。只需更新模型,视图就会自行更新:

export class MyComponent {
    constructor(private route : ActivatedRoute,
      private r : Router) {}

    reloadWithNewId(id:number) {
        this.r.navigateByUrl('my/' + id + '/view');
    }

    ngOnInit() {
      this.sub = this.route.params.subscribe(params => {
         this.paramsChanged(params['id']);
       });
    }

    paramsChanged(id) {
      console.log(id);
      // do stuff with id

    }
}

【讨论】:

  • 使用ngOnInit 钩子与@madhu-ranjan 之类的构造函数相比有什么优势?
  • 你也可以在构造函数中做this.route.params.subscribe(...)的东西。 @Input()s 在执行构造函数时不可用,但在执行 ngOnInit() 时可用(在此实际用例中不相关)。
  • 它工作正常。但是,我使用了激活路由器而不是路由 this.activatedRoute.paramMap.subscribe(params => { this.eci = params.get('id'); }
【解决方案2】:

您可以强制 angular2 重新初始化组件,方法是导航到其他一些 url,然后返回到您想要的。

这是我使用路由器类方法的简单解决方法(参考:https://angular.io/docs/ts/latest/api/router/index/Router-class.html

组件构造函数:

constructor(private router: Router) {}

在模板中(示例):

(click)="onTabChange(id)"

然后在组件类里面:

onTabChange() {
  if (this.router.navigated === false) {
    // Case when route was not used yet
    this.router.navigateByUrl(`/module/${id}`);
  } else {
    // Case when route was used once or more
    this.router.navigateByUrl(`/index`).then(
      () => {
        this.router.navigateByUrl(`/module/${id}`);
      });
  }
}

【讨论】:

  • 有点老套,但它是回答问题的唯一答案,而且比刷新更有效。
  • 只有在有办法从历史记录中删除虚假 URL 的情况下才有效。否则浏览器后退按钮不会执行预期的操作。
  • @benek 使用skipLocationChangethis.router.navigateByUrl('/blank', { skipLocationChange: true })
  • @ThanhNguyen 这对我很有用,但无论如何要避免使用最新的角度版本的虚拟路线?
【解决方案3】:

当您只是更新参数时,不会再次调用构造函数。因为 Component 类已经实例化了,

如果您想检测更改,可以订阅如下参数更改,

  constructor(route: ActivatedRoute) {
    route.params.subscribe(param => {
        let id = param['id '];
        // Do your stuff with id change.
    });
  }

【讨论】:

  • 为什么不直接使用ngOnInit钩子而不是构造函数?
  • @dopatraman,如果您只是通过触发 reloadWithNewId 来更新参数,则不会触发 ngOnInit,因为组件已经初始化。这是Plunker,希望对您有所帮助!!
  • 我也遇到了这个问题,在 ngOnInit 中实现 route.params.subscribe 确实有效:)
【解决方案4】:

我认为changeDetectorRef 是完成这项工作的合适工具:

HTML

<my-component *ngIf="!reloading"
              (loadNext)="onLoadNext()">
</my-component>

TS

  constructor(
    private cdr: ChangeDetectorRef
  ) { }

  onLoadNext() {
      this.reloading = true;
      this.cdr.detectChanges();
      this.reloading = false;
      this.cdr.detectChanges();
  }

您为什么想要这个,而不是像 Günther 提供的答案那样“更新模型并更新视图本身”?这样你就可以确定组件被重新初始化并且没有一些之前的剩余值。这就是为什么我觉得这样做更干净。

示例:https://stackblitz.com/edit/commatrainer-v1

【讨论】:

    猜你喜欢
    • 2018-10-27
    • 1970-01-01
    • 1970-01-01
    • 2020-02-13
    • 2021-12-17
    • 1970-01-01
    • 1970-01-01
    • 2021-02-06
    • 2020-09-29
    相关资源
    最近更新 更多