如何使用angular 2路由器重新加载当前路由


141

我正在使用带有散列分配策略的angular 2。

该组件已加载该路由:

"departments/:id/employees"

到目前为止还好。

在成功批量保存多个已编辑表行之后,我想通过以下方式重新加载当前路由网址:

this.router.navigate([`departments/${this.id}/employees`]);

但是什么也没发生,为什么呢?


看看这个问题的答案:stackoverflow.com/a/44580036/550975
Serj Sagan

Answers:


46

如果您的navigation()没有更改浏览器地址栏上已经显示的URL,则路由器没有任何关系。刷新数据不是路由器的工作。如果要刷新数据,请创建一个注入组件的服务,并在该服务上调用load函数。如果要检索新数据,它将通过绑定更新视图。


2
现在,您说我必须同意,但是... angularjs ui路由器具有重装选项,因此可以重装路由;-)但是,是的,我可以为该提示进行重装数据,实际上很明显...
Pascal

83
我不同意如果您想重新任命警卫人员,例如有人退出了该怎么办?
杰基

1
@Jackie我当时在想,也许您可​​以重新运行警卫队...如果他们内置了重定向功能,那么就可以解决问题。
OldTimeGuitarGuy

11
@YakovFain抱歉,但这是错误的。这意味着您现在对路线行为有了两个真实的来源-一个发生在警卫队期间,另一个发生在组件中。现在,您不仅可能会复制逻辑,而且还反对更自然的数据流:1.更改API,2.刷新路由以从API获取数据的新状态,从而使API成为真理。根本没有理由不给予用户手动重新触发路由的能力,以使自然的数据流可以再次发生。
AgmLauncher '18

4
我认为这不是一个好答案。路由器应该是您数据真实性的来源。如果您必须通过单独的服务重新加载它,则路由器将不再了解最新版本,并且您的组件也将不再依赖路由器作为事实来源。
丹·金

124

现在,可以使用onSameUrlNavigation路由器配置的属性在Angular 5.1中完成此操作。

我添加了一个博客,解释了这里的操作方式,但要点如下

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

在您的路由器配置启用onSameUrlNavigation选项中,将其设置为'reload'。当您尝试导航到已处于活动状态的路由时,这将导致路由器触发事件​​循环。

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

在您的路线定义中,将设置runGuardsAndResolversalways。这将告诉路由器始终启动防护和解析器周期,并触发相关事件。

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

最后,在您要启用重新加载的每个组件中,您需要处理事件。这可以通过导入路由器,绑定到事件并调用初始化方法来完成,该方法可以重置组件的状态并在需要时重新获取数据。

export class InviteComponent implements OnInit, OnDestroy {
 navigationSubscription;     

 constructor(
   // … your declarations here
   private router: Router,
 ) {
   // subscribe to the router events. Store the subscription so we can
   // unsubscribe later.
   this.navigationSubscription = 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.
 }

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

完成所有这些步骤后,您应该已启用路由重载。


有没有一种方法可以重新加载组件而不是调用init函数,
Ebraheem Alrabeea

我不这么认为...除非您离开路线,然后再次返回。初始化函数并不是世界末日,您可以控制初始化,使其具有与重新加载组件相同的作用。您是否有任何特殊原因想要不进行完全重装init
西蒙·麦克利夫

我已经为我的问题找到了解决方案,谢谢您的答复,它对您有所帮助。
Ebraheem Alrabeea

除了重新加载窗口外,如何在Angular 4中做到这一点。
维沙卡

非常适合我的Angular5应用程序!取消订阅ngOnDestroy()非常重要-如果您不这样做,则很有趣:-)
BobC

107

在控制器中创建一个函数,将其重定向到预期的路由,如下所示

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

然后像这样使用它

this.redirectTo('//place your uri here');

此功能将重定向到虚拟路由,并迅速返回到目标路由,而用户不会意识到。


3
谢谢!最好的解决方案。
艾伦·史密斯

该解决方案效果很好,我们可以使用它直到获得更好的解决方案。谢谢@theo。
Sibeesh Venu

12
它就像一个魅力的时候,我用'/'的不是'/DummyComponent'
suhailvs

1
在Angular 7中工作正常,浏览器历史记录中没有问题。由于针对特定组件,我选择使用此解决方案。在我看来,重新加载同一页面通常是一种异常情况,因此使整个应用程序遵循特定的范式似乎有些过头。与其他解决方案相比,它体积小且易于实现。
JE卡特二世

1
好的,它可以工作,但是...它将重新加载您的HomeComponent(或路线“ /”上的所有内容),将在ngOnInit / ngOnDestroy的整个生命周期中完全消失。最好有一些带有虚拟和轻型组件的特定路线,否则您会发现时滞
petronius

77

编辑

对于较新版本的Angular(5.1+),请使用@Simon McClive建议的答案

旧答案

我在针对Angular的GitHub功能请求中找到了此解决方法:

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

this._router.events.subscribe((evt) => {
    if (evt instanceof NavigationEnd) {
        this._router.navigated = false;
        window.scrollTo(0, 0);
    }
});

我尝试将其添加到我的app.component.ts ngOnInit函数中,并且确实可以正常工作。现在,在同一链接上的所有其他点击都将重新加载component和数据。

链接到原始GitHub功能请求

幸得mihaicux2 GitHub上。

我在版本4.0.0-rc.3上测试了import { Router, NavigationEnd } from '@angular/router';


1
刚在Angular 4.4.x中尝试过此方法,即可完全正常工作。谢谢!
Mindsect团队

1
这对我来说非常有用,直到我实现Material的nav-tab-bar来导航应用程序中每个父路线的子路线。一旦用户点击了运行该代码的页面,动画的墨水条就会消失。(为什么?我没有足够的时间或空间来解释...)
andreisrob

3
这是一个非常糟糕的主意-您的ActivatedRoute现在将始终相同。
artuska

1
@AnandTyagi如果您使用的是Angular 5.1+,请尝试SimonMcClives解决方案。也许对您来说更好。
Arg0n

2
这是一个非常糟糕的主意...因为一旦应用了routeReuseStrategy.shouldReuseRoute = false,那么它将加载组件层次结构的每个组件。因此,这意味着您的每个父级和子级组件都会在任何url更改后开始重新加载。因此,使用此框架没有任何意义。
PSabuwala

27

有点棘手:使用相同的路径和一些虚拟参数。例如-

refresh(){
  this.router.navigate(["/same/route/path?refresh=1"]);
}

12
现在:this.router.navigate(['/pocetna'], { queryParams: { 'refresh': 1 } });route.queryParams.subscribe(val => myRefreshMethod())其中route: ActivatedRoute在刷新组件注入...希望它能帮助
INSAN-E

4
目前在Angular 7中,这似乎不再起作用。任何人都可以确认,或者我做错了什么?(我也尝试过insan-e的细微变化。)
pbarranis

2
也许有点丑陋。
Dabbbb。

19

我正在将这个用于Angular 9项目:

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

PS:经过测试,也可以在“ Angular 7、8”上使用


我以为我会对这种解决方案的经验有所了解。对我来说,似乎重新加载了与路线相关的整个组件。在我的情况下,具有不同路由参数的常规router.navigate将保持组件加载,并仅从ngOnInit(基于路由参数)加载新更改。您的解决方案似乎没有执行此操作,它似乎实际上是重新加载了整个组件,然后根据路由参数在ngOnInit中进行了更改。无论如何,这对我来说是一个小小的麻烦,您的解决方案可以满足我的需求。
埃文·塞维

谢谢。完美地工作。
桑托什

17

Angular 2-4路由重新加载hack

对我来说,在根组件(任何路径中都存在的组件)内部使用此方法有效:

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

使用这种方法时要小心,这会全局影响路由器的行为(在子路由之间导航时,父路由始终会重新加载)。
seidme

16

这对我来说就像魅力

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

3
这是最简单的答案。如果可以的话,我会将其标记为可接受的答案。与已接受的答案相反,在某些情况下,您需要重新加载页面上使用的每个单个组件,并且必须分别重新加载每个组件(可能位于不同的路径),即使通过服务也是如此。
Andrew Junior Howard

8

在参数更改上,不会发生重新加载页面。这确实是个好功能。无需重新加载页面,但我们应该更改组件的值。paramChange方法将调用URL更改。这样我们就可以更新组件数据

/product/: id / details

import { ActivatedRoute, Params, Router } from ‘@angular/router’;

export class ProductDetailsComponent implements OnInit {

constructor(private route: ActivatedRoute, private router: Router) {
    this.route.params.subscribe(params => {
        this.paramsChange(params.id);
    });
}

// Call this method on page change

ngOnInit() {

}

// Call this method on change of the param
paramsChange(id) {

}

8

这就是我对Angular 9所做的。我不确定这是否适用于旧版本。

需要重新加载时,需要调用此方法。

 this.router.navigate([], {
    skipLocationChange: true,
    queryParamsHandling: 'merge' //== if you need to keep queryParams
  })

路由器forRoot需要将SameUrlNavigation设置为“重新加载”

 RouterModule.forRoot(appRoutes, {
  // ..
  onSameUrlNavigation: 'reload',
  // ..
})

而且您的每条路线都需要将runGuardsAndResolvers设置为“ always”

{
    path: '',
    data: {},
    runGuardsAndResolvers: 'always'
},

1
这是正确的答案。“ onSameUrlNavigation”自Angular 5开始工作。请投票将其移至顶部
Yaroslav Yakovlev

这对我不起作用。安德里斯的下面做到了。尽管安德里斯(Andris)的重装不像实际的常规路线导航那样“干净”。它似乎没有重新加载整个页面,但似乎确实重新加载了与路由关联的整个组件。我只需要子组件即可根据路由参数重新加载,而不是与路由关联的整个组件。无论如何,它运行良好。只是认为我会喜欢我的经历。
Evan Sevy

4

对我来说,

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

1
不建议!人们在整个SO中以不同的方式不断发布此解决方案。是的,它可能可以解决您眼前的问题,但是您稍后会忘记实现了该问题,并且将花费数小时来尝试找出您的应用为何会出现怪异行为的原因。
Helzgate

如果必须使用此功能,请使用Ebraheem Alrabee的解决方案,并将其仅应用于一条路线。
Helzgate

4

据我所知,Angular 2中的路由器无法做到这一点。但是您可以这样做:

window.location.href = window.location.href

重新加载视图。


3
这将刷新整个应用程序,而不仅仅是当前路径!
rostamiani

@HelloWorld-在哪里将逻辑放在角度7中?
Pra_A

不要紧,它的角版本-这只是普通的js代码
HelloWorld的

将其放在点击功能上。window.location.href ='/'或'/ login',它们在app-routing.module.ts中定义。在我的情况下,当用户注销时,它应该返回登录屏幕,因此在注销时,我清除所有身份验证数据,并在成功时使用window.location.href ='/'。这意味着重新加载loagin页面并再次运行所有javascript。对于正常的路线更改,在不需要重新运行功能的情况下,我不建议您这样做。
Ali Exalter

我相信这可能会完全重置您的NgRx存储-因此,您已经获取的所有数据都会丢失。
John Q

3

找到了一种快速而直接的解决方案,该解决方案不需要修改angular的内部工作原理:

基本上:只需使用相同的目标模块创建备用路由,然后在它们之间切换即可:

const routes: Routes = [
  {
    path: 'gesuch',
    loadChildren: './sections/gesuch/gesuch.module#GesuchModule'
  },
  {
    path: 'gesuch-neu',
    loadChildren: './sections/gesuch/gesuch.module#GesuchModule'
  }
];

这里是切换菜单:

<ul class="navigation">
    <li routerLink="/gesuch-neu" *ngIf="'gesuch' === getSection()">Gesuch</li>
    <li routerLink="/gesuch" *ngIf="'gesuch' !== getSection()">Gesuch</li>
</ul>

希望能帮助到你 :)


如果备用路由具有参数,并且您想在参数更改时重新加载怎么办?
Mukus


2

就我而言:

const navigationExtras: NavigationExtras = {
    queryParams: { 'param': val }
};

this.router.navigate([], navigationExtras);

工作正常


2

实现OnInit并在route.navigate()方法中调用ngOnInit()

看一个例子:

export class Component implements OnInit {

  constructor() {   }

  refresh() {
    this.router.navigate(['same-route-here']);
    this.ngOnInit();   }

  ngOnInit () {

  }

2

通过使用虚拟组件和路由解决了类似的情况reload,实际上可以做到redirect。绝对不能涵盖所有用户方案,而仅适用于我的方案。

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Http } from '@angular/http';

@Component({
  selector: 'reload',
  template: `
    <h1>Reloading...</h1>
  `,
})
export class ReloadComponent implements OnInit{
  constructor(private router: Router, private route: ActivatedRoute) {
  }

  ngOnInit() {
    const url = this.route.snapshot.pathFromRoot.pop().url.map(u => u.path).join('/');
    this.router.navigateByUrl(url);
  }
}

使用通配符将路由连接为捕获所有URL:

import { RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';
import { LoginViewComponent } from './views/login/login.component';
import { HomeViewComponent } from './views/home/home.component';
import { ReloadComponent } from './views/reload/reload.component';

@NgModule({
  declarations: [ 
    LoginViewComponent, HomeViewComponent, ReloadComponent
  ],
  imports: [
    RouterModule.forRoot([
      { path: 'login', component: LoginViewComponent },
      { path: 'home', component: HomeViewComponent },
      { 
        path: 'reload',
        children: [{
          path: '**',
          component: ReloadComponent 
        }]
      },
      { path: '**', redirectTo: 'login'}
    ])
  ],
  exports: [
    RouterModule,
  ],
  providers: [],

})
export class AppRoutingModule {}

要使用此功能,我们只需要将重载添加到我们想去的URL:

  this.router.navigateByUrl('reload/some/route/again/fresh', {skipLocationChange: true})

2

有多种方法可以刷新当前路线

更改路由器行为(自Angular 5.1起) 将路由器onSameUrlNavigation设置为“重新加载”。这将在同一URL导航上发出路由器事件。

  • 然后,您可以通过订阅路线来处理它们
  • 您可以将其与runGuardsAndResolvers结合使用以重新运行解析器

保持路由器不变

  • 在URL中传递带有当前时间戳的refresh queryParam,并在路由组件中订阅queryParams。
  • 使用路由器出口的Activate Event来获取路由组件的保留。

我在https://medium.com/@kevinkreuzer/refresh-current-route-in-angular-512a19d58f6e下写了更详细的解释

希望这可以帮助。


1

假设您要刷新的组件的路由为view,然后使用以下命令:

this.router.routeReuseStrategy.shouldReuseRoute = function (future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot) {
  if (future.url.toString() === 'view' && curr.url.toString() === future.url.toString()) {
    return false;
  }
  return (future.routeConfig === curr.routeConfig);
}; 

您可以debugger在方法中添加一个内部信息,以了解导航到后的确切路线是什么"departments/:id/employees"


1

一种解决方案是传递一个虚拟参数(即,以秒为单位的时间),以这种方式始终重新加载链接:

this.router.navigate(["/url", {myRealData: RealData, dummyData: (new Date).getTime()}])

1

我正在使用setTimeoutnavigationByUrl解决此问题...而且它对我来说很好。

它被重定向到其他URL,而是再次出现在当前URL中。

 setTimeout(() => {
     this.router.navigateByUrl('/dashboard', {skipLocationChange: false}).then(() =>
           this.router.navigate([route]));
     }, 500)

1

我相信这已经在Angular 6+中解决了(本机)。检查

但这适用于整个路线(也包括所有子路线)

如果要定位单个组件,请执行以下操作:使用变化的查询参数,以便您可以随意导航多次。

导航点(类)

   this.router.navigate(['/route'], {
        queryParams: { 'refresh': Date.now() }
    });

在您要“刷新/重新加载”的组件中

// . . . Component Class Body

  $_route$: Subscription;
  constructor (private _route: ActivatedRoute) {}

  ngOnInit() {
    this.$_route$ = this._route.queryParams.subscribe(params => {
      if (params['refresh']) {
         // Do Something
         // Could be calling this.ngOnInit() PS: I Strongly advise against this
      }

    });
  }

  ngOnDestroy() {
    // Always unsubscribe to prevent memory leak and unexpected behavior
    this.$_route$.unsubscribe();
  }

// . . . End of Component Class Body

1

非常令人沮丧的是,Angular 似乎仍然没有为此提供好的解决方案。我在这里提出了一个github问题:https : //github.com/angular/angular/issues/31843

同时,这是我的解决方法。它基于上面建议的其他一些解决方案,但我认为它更强大。它涉及将路由器服务包装在“ ReloadRouter”中,该服务负责重新加载功能,还RELOAD_PLACEHOLDER向核心路由器配置添加了。这用于临时导航,避免触发任何其他路线(或警卫)。

注意:ReloadRouter需要重新加载功能的情况下使用。Router否则请使用普通纸。

import { Injectable } from '@angular/core';
import { NavigationExtras, Router } from '@angular/router';

@Injectable({
  providedIn: 'root'
})
export class ReloadRouter {
  constructor(public readonly router: Router) {
    router.config.unshift({ path: 'RELOAD_PLACEHOLDER' });
  }

  public navigate(commands: any[], extras?: NavigationExtras): Promise<boolean> {
    return this.router
      .navigateByUrl('/RELOAD_PLACEHOLDER', {skipLocationChange: true})
      .then(() => this.router.navigate(commands, extras));
  }
}

1

导入RouterActivatedRoute@angular/router

import { ActivatedRoute, Router } from '@angular/router';

注入RouterActivatedRoute(如果您需要从URL获得任何内容)

constructor(
    private router: Router,
    private route: ActivatedRoute,
) {}

如果需要,请从URL获取任何参数。

const appointmentId = this.route.snapshot.paramMap.get('appointmentIdentifier');

使用技巧,方法是导航到虚拟或主URL,然后导航到实际URL,以刷新组件。

this.router.navigateByUrl('/appointments', { skipLocationChange: true }).then(() => {
    this.router.navigate([`appointment/${appointmentId}`])
});

就你而言

const id= this.route.snapshot.paramMap.get('id');
this.router.navigateByUrl('/departments', { skipLocationChange: true }).then(() => {
    this.router.navigate([`departments/${id}/employees`]);
});

如果您使用的是虚拟路由,那么如果您实现了未找到的网址(如果该网址与任何网址都不匹配),那么您会看到标题闪烁“未找到”。


0

订阅路由参数更改

    // parent param listener ie: "/:id"
    this.route.params.subscribe(params => {
        // do something on parent param change
        let parent_id = params['id']; // set slug
    });

    // child param listener ie: "/:id/:id"
    this.route.firstChild.params.subscribe(params => {
        // do something on child param change
        let child_id = params['id'];
    });

0

如果要通过路由器链接更改路由,请遵循以下步骤:

  constructor(public routerNavigate: Router){

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

          this.router.events.subscribe((evt) => {

            if (evt instanceof NavigationEnd) {

                this.router.navigated = false;
             }
          })
      }

0

您应该在RouterModule中使用“ onSameUrlNavigation”属性,然后订阅路由事件 https://blog.angularindepth.com/refresh-current-route-in-angular-512a19d58f6e


欢迎使用指向解决方案的链接,但是请确保没有该链接的情况下,您的回答是有用的:在链接周围添加上下文,以便您的其他用户可以了解它的含义和含义,然后引用您所使用页面中最相关的部分如果目标页面不可用,请重新链接。只是链接的答案可能会被删除。
Alessio

0

决定何时应存储路线,将false返回给

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

并将router的导航值设置为false,这表明该路由从未路由

this.mySubscription = this.router.events.subscribe(event => {
    if (event instanceof NavigationEnd) {
        this.router.navigated = false;
    }
});

0

我已经尝试了一些修复程序,但都无济于事。我的版本很简单:将新的未使用参数添加到查询参数中

            if (force) {
                let key = 'time';

                while (key in filter) {
                    key = '_' + key;
                }

                filter[key] = Date.now();
            }

            this.router.navigate(['.', { filter: JSON.stringify(filter) }]);

0

window.location.replace

//使用反引号将路线括起来

window.location.replace(departments/${this.id}/employees

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.