【问题标题】:Can't reload/refresh active route无法重新加载/刷新活动路由
【发布时间】:2016-10-28 10:29:08
【问题描述】:

我最近更新到了新的 RC3 和 Router3alpha,似乎有些事情发生了变化。

我注意到单击活动路由的链接不再导致重新加载组件。如何使用新的 router3 实现此行为?

我的链接看起来像

<a [routerLink]="['/link1']">Link1</a>

为了测试,我只是在 ngOnInit 中使用了一个随机数:

export class LinkoneComponent implements OnInit 
{

    public foo: number;
    constructor() {}

    ngOnInit() 
    {
        this.foo = Math.floor(Math.random() * 100) + 1;
    }

}

在路由之间切换时效果很好,但是单击当前活动的路由不会导致组件重新加载。

【问题讨论】:

  • 删除 routerLink 并添加 (click) 事件,这将重新加载页面 router.navigateByUrl('/link1');
  • 有趣的想法,但这不可能是“官方”的方式,不是吗?
  • 这叫做程序化导航,查看Router 3的文档
  • 这也不适用于活动路由...
  • 您可以在每次点击 URL 时添加一个“无意义”参数,例如第二次点击路由器导航到 /link1#2,第三次点击 /link1#3

标签: angular angular2-routing angular2-router3


【解决方案1】:

目前不支持此功能。如果仅参数值更改但路由保持不变,则不会重新创建组件。

另见https://github.com/angular/angular/issues/9811

您可以订阅参数以在参数更改以重新初始化组件实例时收到通知。

另见https://stackoverflow.com/a/38560010/217408

【讨论】:

  • 是的……我明白了。我会给你我的赏金积分;)我做了一个丑陋的 hack - 重定向到虚拟 Url,然后返回到所需的 Url :) 这会导致组件被重用,但它是一个丑陋的 hack。你打算让它可配置吗?
  • 不知道有没有计划实施。我认为下一个版本应该支持router.navigate() 的参数以跳过历史更新,这样您就不会将这两个重定向添加到历史记录中。
  • 是的。这会很好,但这不是我原来的问题。这当然会领先一步:)感谢您的回答。
  • 你也可以试试我在stackoverflow.com/questions/38971660/…的建议
【解决方案2】:

从 Angular 5.1 开始,现在可以使用 onSameUrlNavigation 来完成此操作 配置选项作为内置 Angular 路由器的一部分。尽管从文档中看不明显,但设置和开始使用相当简单。

您需要做的第一件事是在您的app.routing.ts 中设置选项(如果您有一个或配置应用路由的文件)。

onSameUrlNavigation 'reload' 或 false 有两个可能的值。默认值为false,当路由器被要求导航到活动路由时,不会发生任何事情。我们想将此值设置为reload。值得注意的是reload实际上并没有做重新加载路由的工作,它只是重新触发路由器上的事件,然后我们需要挂钩。

@NgModule({
  imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload'})],
  exports: [RouterModule],
})

要确定实际触发这些事件的时间,您需要在路由中指定 runGuardsAndResolvers 配置选项。这可以取三个值...

paramsChange - 仅在路由参数发生变化时触发,例如/user/:id 中的 id 发生变化的地方

paramsOrQueryParamsChange - 当路由参数改变或查询参数改变时触发。例如id 或 limit 属性更改在 /user/:id/invites?limit=10

always - 导航时总是触发

在这种情况下,我们希望始终指定。示例路线如下所示。

export const routes: Routes = [
  {
    path: 'invites',
    component: InviteComponent,
    children: [
      {
        path: '',
        loadChildren: './pages/invites/invites.module#InvitesModule',
      },
    ],
    canActivate: [AuthenticationGuard],
    runGuardsAndResolvers: 'always',
  }
]

那是您配置的路由器。下一步是实际处理其中一个组件中的事件。您需要将路由器导入到您的组件中,然后挂钩到事件中。在这个例子中,我已经挂钩了NavigationEnd 事件,一旦路由器完成从一个路由到下一个路由的导航,就会触发该事件。由于我们配置应用程序的方式,即使您尝试导航到当前路线,它现在也会触发。

export class InviteComponent implements OnInit {
  constructor(
    // ... your declarations here
    private router: Router,
  ) {
    // subscribe to the router events
    this.router.events.subscribe((e: any) => {
      // If it is a NavigationEnd event re-initalise the component
      if (e instanceof NavigationEnd) {
        this.initialiseInvites();
      }
    });
  }

  initialiseInvites() {
    // Set default values and re-fetch any data you need.
  }
}

繁重的工作进入 initialiseInvites() 方法,在这里您将属性重置为其默认值并从服务中获取数据以使组件恢复其初始状态。

您需要在每个想要在单击或通过某种形式的刷新按钮刷新时重新加载的组件上重复此模式,并确保将runGuardsAndResolvers 选项添加到路由文件中的每个路由。

【讨论】:

  • 我仍然不认为这是大多数人想要重新加载或刷新页面时理想的解决方案。我认为一个很好的解决方案就是重新创建组件,包括销毁和重建组件 dom,这似乎并不容易。必须用这样的横切关注点修改所有组件并不理想。角度有点糟 imo。
  • 我也不喜欢这个解决方案。我在一个子路由中,导航到另一个子路由,它们共享相同的数据,在父路由中解析。我刚刚向服务器提交了更新,所以我想以编程方式重新加载整个路由,这样父解析器将再次触发。我没有导航到同一个 URL,我不想触发重新加载每次我这样做...
  • 我错过了 runGuardsAndResolvers: 'always' 谢谢
  • 正是我想要的!
【解决方案3】:

Angular 2-4 当前路线重载技巧

对我来说,使用这种方法是可行的:

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

  let currentUrl = this.router.url + '?';

  this.router.navigateByUrl(currentUrl)
    .then(() => {
      this.router.navigated = false;
      this.router.navigate([this.router.url]);
    });
  }

您可以将此方法附加到当前组件上的单击事件以重新加载它。

【讨论】:

    【解决方案4】:

    这对我有用,取自 this:

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

    现在你可以像这样使用:this.redirectTo(this.router.url);

    【讨论】:

    • 为我工作但不明白最后一行“现在你可以.. 像这样”
    【解决方案5】:

    这是我能想出的解决这个烦人问题的最佳技巧:

        var currentUrl = this.router.url;
        var refreshUrl = currentUrl.indexOf('someRoute') > -1 ? '/someOtherRoute' : '/someRoute';
        this.router.navigateByUrl(refreshUrl).then(() => this.router.navigateByUrl(currentUrl));
    

    这可行,但它仍然是一个 hack,我讨厌 Angular 团队没有提供 reload() 方法

    【讨论】:

    • Hackish 和恼人,但它对我有用。不得不为 Angular 4 切换到 navigate([refreshUrl]);,但其他方面都很完美。当这是一个如此常见的用例时,没有重新加载方法是愚蠢的。例如,我需要能够快速切换用户并重新加载当前路线以进行客户演示。我的所有组件都相互不了解(应该如此),唯一的共享服务无法刷新主要组件。
    • 感谢您的解决方案。我正在努力更新与 WorkflowService 相关的组件,因为该应用程序不允许刷新实际组件...您应该获得奖牌...
    【解决方案6】:

    对于 Angular 2 rc7 - 路由器 3.0

    将 index.html 中的基本 url 更改为 &lt;script&gt;document.write('&lt;base href="/" /&gt;');&lt;/script&gt;

    【讨论】:

    • 如果有帮助,你试过了吗?我认为这没有帮助
    • 'document' 不适用于 Angular Universal
    • @Francesco In index.html??
    【解决方案7】:
    if (currentUrl.indexOf('/settings') > -1) {
        this.router.navigateByUrl('/communication').then(() => this.router.navigateByUrl('/settings'));
    } else {
        this.router.navigate(['/settings']);
    }
    

    【讨论】:

      【解决方案8】:

      如果你真的需要在每次 routerLink 点击时欺骗路由器重新加载组件,你可以在你的组件中使用以下代码

      constructor(private router: Router){
       // override the route reuse strategy
       this.router.routeReuseStrategy.shouldReuseRoute = function(){
          return false;
       }
      
       this.router.events.subscribe((evt) => {
          if (evt instanceof NavigationEnd) {
             // trick the Router into believing it's last link wasn't previously loaded
             this.router.navigated = false;
             // if you need to scroll back to top, here is the right place
             window.scrollTo(0, 0);
          }
      });
      
      }
      

      希望对你有帮助

      【讨论】:

        【解决方案9】:

        我遇到了同样的问题,我在我的应用程序模块中使用 LocationStrategy 解决了它。这就是我如何实现并将解决所有路由问题。

        在app.module.ts

        • 添加 HashLocationStrategy 和 LocationStrategy

          import { HashLocationStrategy, LocationStrategy } from '@angular/common';

        • 添加 NgModule Provider

        {
           provide: LocationStrategy,
           useClass: HashLocationStrategy
         }
        

        决赛 app.module.ts 看起来像这样

        import { NgModule }       from '@angular/core';
        import { BrowserModule  } from '@angular/platform-browser';
        import { AppComponent }   from './app.component';
        import { HashLocationStrategy, LocationStrategy } from '@angular/common';
        
        @NgModule({
            declarations: [AppComponent],
            imports: [BrowserModule],
            providers: [
                          {
                             provide: LocationStrategy, 
                             useClass: HashLocationStrategy
                          }
                        ],
        })
        
        export class AppModule {}
        

        有关更多信息,您可以点击这些链接 HashLocationSt

        注意:上述策略会在您不喜欢的 URL 中添加 #。所以我使用了替代方法:

        替代方法

        除了使用HashLocationStrategy,您还可以使用PathLocationStrategy。

        执行以下步骤,这将删除 # 并在上述方法中按预期工作

        • 从@angular/common 导入 PathLocationStrategy
        import { LocationStrategy, PathLocationStrategy } from '@angular/common';
        
        • 在提供者中将HashLocationStrategy 替换为PathLocationStrategy
        • 确保您的index.html 具有如下基本href。

        &lt;base href="/"&gt;

        【讨论】:

          【解决方案10】:

          JavaScript Window 对象公开了一个 location 成员,该成员具有一个名为 reload 的函数。

          使用,

          window.location.reload();
          

          参考: https://www.w3schools.com/jsref/met_loc_reload.asp

          【讨论】:

            【解决方案11】:

            在我看来,您可以在打字稿中使用window.location.reload()。 这种方式既简单又安全,因为它是浏览器功能的一部分。

            【讨论】:

            • 然后重新加载整个 Angular 应用程序?非常糟糕的主意
            • 仅当您想保留应用程序而不丢失当前信息时,这不是一个好主意。但是如何重新加载或刷新页面? (我认为另一种方式是附加或分离您要刷新的模板的服务,但此任务需要更多努力)
            • 确实是个坏主意。与仅更改路线相比,重新加载 Angular 应用程序非常缓慢。
            • 但是如果你想“清除”当前状态是个好主意
            猜你喜欢
            • 2017-10-24
            • 2017-02-25
            • 1970-01-01
            • 2020-05-08
            • 2019-08-22
            • 1970-01-01
            • 1970-01-01
            • 2018-02-17
            • 2017-04-15
            相关资源
            最近更新 更多