【问题标题】:如何在 Angular 中刷新组件
【发布时间】:2018-05-28 13:50:36
【问题描述】:

我正在做一个 Angular 项目。我正在为组件中的刷新操作而苦苦挣扎。

我想在按钮单击时刷新路由器的组件。 当我单击它时,我有刷新按钮,组件/路由器需要刷新。

我试过window.location.reload()location.reload() 这两个不适合我的需要。如果有人知道,请提供帮助。

【问题讨论】:

  • 你能在这个问题中分享你的代码吗?你正在尝试什么。
  • 代码复杂,有N行代码,难以分享
  • @Saurabh,通常不需要重新加载组件。您可以拥有一个功能(例如,调用“重启”)并在您的按钮刷新中调用该功能。如果您需要订阅更改路径或其他服务,请使用函数 ngOnInit -您的组件必须扩展 OnInit-,而不是构造函数
  • 这就是我使用 Angular 9 stackoverflow.com/a/60909777/1072395 所做的

标签: angular routes components refresh


【解决方案1】:

经过一些研究和修改我的代码如下,该脚本对我有用。我刚刚添加了条件:

this.router.navigateByUrl('/RefreshComponent', { skipLocationChange: true }).then(() => {
    this.router.navigate(['Your actualComponent']);
}); 

【讨论】:

  • 我在可注入服务中使用它。我用一个变量替换了"your actualComponent"。在调用navigateByUrl 之前将变量设置为this.location.path()。这样,无需从调用组件传递任何参数或复制/传递路由。
  • 你能解释一下什么是'RefrshComponent'和'Your actualComponent'吗?
  • 大多数人都可以使用'/',其中/RefrshComponent 是,而对于[Your actualComponent"],您只需传递您想要重新加载的url(和/或参数),例如@987654329 @。这种 hack 本质上是重定向到顶部 URL,然后很快回到预期的 URL,这对于大多数用户来说是不明显的,并且似乎是实现这一目标的最优雅的 hack。
  • 我同意这绝对可以工作......但它在我的应用程序(Angular 6)中失败了。如果我使用'/' 作为我的虚拟路线,它会(通过redirectTo)到我的app-routing.module.ts 重定向到''(空字符串)的路径并停止,而不是继续完成路线在navigate() 电话中。如果我使用一个不存在的字符串(例如/foo)作为我的虚拟路由,它会(通过redirectTo)到我的app-routing.module.ts 重定向到**(其他所有内容)并再次停止,不去真正的路线。奇怪的是,网址栏确实更改为真实路线。有什么不同的想法吗?
  • 如果不小心使用会导致无限重定向循环
【解决方案2】:

使用 this.ngOnInit(); 重新加载相同的组件,而不是重新加载整个页面!!

DeleteEmployee(id:number)
  {
    this.employeeService.deleteEmployee(id)
    .subscribe( 
      (data) =>{
        console.log(data);

        this.ngOnInit();

      }),
      err => {
        console.log("Error");
      }   
  }

【讨论】:

  • 虽然这可能会回答作者的问题,但它缺少一些解释性文字和/或文档链接。如果没有围绕它们的一些短语,原始代码 sn-ps 并不是很有帮助。您可能还会发现how to write a good answer 非常有帮助。请编辑您的答案。
  • 这是比所选答案更好的输入,但缺乏解释。在我的具体情况下,我必须刷新一个子组件。在这种情况下,有几种方法,但建议使用服务或将事件从父级广播到子级。
  • 同意,这仅在您想从组件内刷新组件时才有效 - 如果您正在处理子/外部组件,this.ngOnInit() 将不起作用
  • 即使它适用于组件,它也不会重置表单验证器。
  • 完美运行,谢谢。关于 AFAIC 的解释,代码说明了一切。
【解决方案3】:

将此添加到所需组件的构造函数的代码对我有用。

this.router.routeReuseStrategy.shouldReuseRoute = function () {
  return false;
};

this.mySubscription = this.router.events.subscribe((event) => {
  if (event instanceof NavigationEnd) {
    // Trick the Router into believing it's last link wasn't previously loaded
    this.router.navigated = false;
  }
});

确保在ngOnDestroy() 中从这个mySubscriptionunsubscribe

ngOnDestroy() {
  if (this.mySubscription) {
    this.mySubscription.unsubscribe();
  }
}

更多详情请参阅此主题 - https://github.com/angular/angular/issues/13831

【讨论】:

    【解决方案4】:

    幸运的是,如果您使用的是 Angular 5.1+,则无需再实施 hack,因为已添加本机支持。您只需在 RouterModule 选项中将 onSameUrlNavigation 设置为“重新加载”

    @ngModule({
     imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: ‘reload’})],
     exports: [RouterModule],
     })
    

    更多信息可以在这里找到:https://medium.com/engineering-on-the-incline/reloading-current-route-on-click-angular-5-1a1bfc740ab2

    【讨论】:

    • 你也可以使用注入路由器的router.onSameUrlNavigation = 'reload'属性。
    • 使用 Angular 6,对我来说这没什么区别,即组件没有重新加载。但是,接受的答案有效。
    • 虽然在文档中并不完全清楚,onSameUrlNavigation 旨在重新调用 Guards/Resolvers,而不是重新加载已经路由的组件。有关更多信息,请参阅github.com/angular/angular/issues/21115。此解决方案适用于使用 Guards/Resolvers 的更大更复杂的应用程序,但对于简单的示例将失败。
    • 是的,onSameUrlNavigation 将再次触发导航事件,但这不会重新加载组件
    • 是的!该解决方案有效。也许您可以在回答中提及更多细节。
    【解决方案5】:

    这有点开箱即用,我不知道这是否对你有帮助,但你尝试过

    this.ngOnInit();

    它是一个函数,因此您在其中的任何代码都会像刷新一样被调用。

    【讨论】:

      【解决方案6】:

      另一种无需显式路由的方式:

      async reload(url: string): Promise<boolean> {
        await this.router.navigateByUrl('.', { skipLocationChange: true });
        return this.router.navigateByUrl(url);
      }
      

      【讨论】:

      • 完美解决方案。它对我有用,没有副作用。
      • 实际上它给出了错误:无法匹配任何路由。 URL 段:'.'如果您在应用程序路由中没有路由
      【解决方案7】:

      这可以通过 hack 来实现,导航到一些示例组件,然后导航到要重新加载的组件。

      this.router.navigateByUrl('/SampleComponent', { skipLocationChange: true });
      this.router.navigate(["yourLandingComponent"]);
      

      【讨论】:

      • SampleComponent 表示它应该是一个空组件还是我项目中的另一个组件?
      • 应该是虚拟的,可以为空
      • 好的,我试试这个
      • 如果我给出 true 我收到一条错误消息:[ts] 类型“true”与类型“NavigationExtras”没有共同的属性
      • @SreehariBallampalli 检查更新的答案,您需要传递一个对象 { skipLocationChange: true }
      【解决方案8】:

      只需按照以下步骤操作:

      1. 在您的 app-routing.modules.ts 中添加{onSameUrlNavigation: 'reload'},如下所示

      @NgModule({
      进口:[RouterModule.forRoot(路线,{onSameUrlNavigation:'重新加载'})],
      出口:[路由器模块]
      })

      1. 在您的组件 ts 文件构造函数中添加 this.router.routeReuseStrategy.shouldReuseRoute = () =&gt; false 如下:
      constructor(private router: Router) {
            this.router.routeReuseStrategy.shouldReuseRoute = () => false;
        }
      
      1. 现在单击按钮并调用 ajax 服务器调用,从服务器获取所需数据并将 TS 文件中的全局变量替换为新数据。
      2. 最后拨打this.router.navigate([/sameRoute]);。 将 sameRoute 替换为您的路由网址。

      3. 确保在刷新按钮的onClick 方法最后返回false,否则会导致主路由页面而不是相同页面重新加载。

        这些步骤将重新加载您的页面。 :)

      更多详情:https://medium.com/engineering-on-the-incline/reloading-current-route-on-click-angular-5-1a1bfc740ab2

      我正在使用 Angular 12。

      【讨论】:

        【解决方案9】:

        之前的一些答案有问题:

        1. 不应直接调用诸如 ngOnInit() 之类的生命周期方法。
        2. 重新导航到某个 URL 不是最佳解决方案,尤其是当您动态加载的组件只是大页面的一小部分时

        这对我有用(我不知道它是否值得推荐或最佳)

        1. 在要动态加载的组件中,添加对ChangeDetectorRefpublic引用。
        2. 我假设动态加载的数据有一些输入数据,(示例中为“tags”),这些数据在事后更新并造成渲染问题。
          @Input()
          tags: string[] = [];
        
          constructor(public changeDetector: ChangeDetectorRef )
        
        1. 在做动态加载的父组件中,在动态创建子组件并可能给它设置一些数据后,调用创建的实例的changeDetector.markForCheck()如下:
          constructor(private vcrf: ViewContainerRef, private cfr: ComponentFactoryResolver, private elementRef: ElementRef) {
          }
        
          public loadComponent(): void {
        
            const componentFactory = this.cfr.resolveComponentFactory(TagsListComponent);
            const component = this.container.createComponent(componentFactory);
            component.instance.tags = /* whatever data we want to pass */;
            component.instance.changeDetector.markForCheck();
            ...
        

        loadComponent() 是一个可以调用的自定义函数,例如,当父页面滚动到父组件中的某个位置时,指示应该显示动态组件。

        【讨论】:

          【解决方案10】:

          在我的应用程序中,我有组件,所有数据都来自我在组件的构造函数中调用的 API。 有一个按钮,我可以通过它更新我的页面数据。在按钮上单击我已将数据保存在后端并刷新数据。 因此,根据我的要求重新加载/刷新组件只是刷新数据。 如果这也是您的要求,请使用在组件的构造函数中编写的相同代码。

          【讨论】:

            【解决方案11】:

            只需从角度路由器更改routeReuseStrategy

            this._router.routeReuseStrategy.shouldReuseRoute = function () {
                  return false;
                };
            

            将routerproperty“navigated”设置为false:

            this._router.navigated = false;
            

            然后导航到您的组件:

            this._router.navigate(['routeToYourComponent'])
            

            之后恢复旧的/默认的 routeReuseStrategy:

            this._router.routeReuseStrategy.shouldReuseRoute = function (future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
                      return future.routeConfig === curr.routeConfig;
            

            你也可以用这个来做服务:

            @Injectable({
              providedIn: 'root'
            })
            export class RouterService {
            
              constructor(
                private _activatedRoute: ActivatedRoute,
                private _router: Router
              ) { }
            
              reuseRoutes(reuse: boolean) {
                if (!reuse) {
                  this._router.routeReuseStrategy.shouldReuseRoute = function () {
                    return false;
                  };
                }
                if (reuse) {
                  this._router.routeReuseStrategy.shouldReuseRoute = function (future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
                    return future.routeConfig === curr.routeConfig;
                  };
                }
              }
            
              async refreshPage(url?: string) {
                this._router.routeReuseStrategy.shouldReuseRoute = function () {
                  return false;
                };
            
                this._router.navigated = false;
            
                url ? await this._router.navigate([url]) : await this._router.navigate([], { relativeTo: this._activatedRoute });
            
                this._router.routeReuseStrategy.shouldReuseRoute = function (future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
                  return future.routeConfig === curr.routeConfig;
                };
              }
            }
            

            【讨论】:

              【解决方案12】:

              kdo

              // reload page hack methode
              
              push(uri: string) {
                  this.location.replaceState(uri) // force replace and no show change
                  await this.router.navigate([uri, { "refresh": (new Date).getTime() }]);
                  this.location.replaceState(uri) // replace
                }
              

              【讨论】:

                【解决方案13】:
                constructor(private router:Router, private route:ActivatedRoute ) { 
                }
                
                onReload(){
                 this.router.navigate(['/servers'],{relativeTo:this.route})
                }
                

                【讨论】:

                  【解决方案14】:

                  只需这样做:(对于角度 9)

                  import { Inject } from '@angular/core';    
                  import { DOCUMENT } from '@angular/common';
                  
                  constructor(@Inject(DOCUMENT) private document: Document){ }
                  
                  someMethode(){ this.document.location.reload(); }
                  

                  【讨论】:

                  • 请阅读 OPs 的评论,刷新整个页面不是他的选择,它违背了最初拥有 Angular 的目的
                  • 这个问题只要求重新加载组件而不是整个页面。
                  【解决方案15】:

                  html文件

                  <a (click)= "getcoursedetails(obj.Id)" routerLinkActive="active" class="btn btn-danger">Read more...</a>
                  

                  ts 文件

                    getcoursedetails(id)
                    { 
                    this._route.navigateByUrl('/RefreshComponent', { skipLocationChange: true }).then(() => {
                      this._route.navigate(["course",id]);
                    }); 
                  

                  【讨论】:

                    【解决方案16】:

                    router.navigate['/path'] 只会带你到指定的路径
                    使用router.navigateByUrl('/path')
                    它重新加载整个页面

                    【讨论】:

                      【解决方案17】:

                      reload () { this.ngOnInit(); }

                      【讨论】:

                        【解决方案18】:

                        在我的情况下,我需要重新加载特定路由(不是全部在应用程序中),因此添加全局设置 {onSameUrlNavigation: 'reload'} 没有效果,而在组件中添加 this.router.routeReuseStrategy.shouldReuseRoute = () =&gt; false 可以工作,但会修改路由器的全局设置。

                        解决方案是将原始路由器配置保存到变量中,然后在组件的构造函数中更改它,如问题的第一个答案所示@abhishek-singh。

                        private routeReuseStrategy:any;
                        
                          constructor(
                            private router:Router
                          ) {
                            this.routeReuseStrategy = this.router.routeReuseStrategy.shouldReuseRoute;
                            this.router.routeReuseStrategy.shouldReuseRoute = () => false;
                          }

                        并且在退出路径时,使用 OnDestroy 挂钩重新映射原始配置。

                           public ngOnDestroy():void
                           {
                             this.router.routeReuseStrategy.shouldReuseRoute = this.routeReuseStrategy;
                           }

                        【讨论】:

                          【解决方案19】:

                          调用ngOnInit() 不适用于我的复杂组件,我最终使用了这个

                          reloadCurrentRoute() {
                              let currentUrl = this.router.url;
                              this.router.navigateByUrl('/', {skipLocationChange: true}).then(() => {
                                  this.router.navigate([currentUrl]);
                              });
                          }
                          

                          【讨论】:

                            【解决方案20】:

                            像这样以 Angular 2 刷新(硬方式)页面的其他方式 看起来像 f5

                            import { Location } from '@angular/common';
                            
                            constructor(private location: Location) {}
                            
                            pageRefresh() {
                               location.reload();
                            }
                            

                            【讨论】:

                            • 他说不适合重新加载整个页面,这会重新加载整个页面,而不仅仅是单个/多个组件。
                            • 我最终使用了这个,除了角度定位服务没有重新加载,所以我使用了窗口。
                            猜你喜欢
                            • 2017-12-29
                            • 2022-01-02
                            • 2017-08-05
                            • 2018-08-03
                            • 2017-03-05
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2019-09-30
                            相关资源
                            最近更新 更多