ChatGPT解决这个技术问题 Extra ChatGPT

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

我正在使用 angular 2 和 hashlocation 策略。

组件使用该路由加载:

"departments/:id/employees"

到目前为止还好。

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

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

但是什么都没有发生,为什么?

看看这个对类似问题的回答:stackoverflow.com/a/44580036/550975
解决方案: 订阅查询参数并从那里加载数据。没有技巧,只是“URL 已更改 --> 数据已重新加载”(包括第一次)。 更多: stackoverflow.com/a/68503542/7573844
原因:如果可能的话,Angular 重用组件以节省计算机的资源。加载数据是您的自定义逻辑,Angular 无法为您完成。

G
Ganesh

在控制器中创建一个函数,像这样重定向到预期的路由

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

然后像这样使用它

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

这个函数将重定向到一个虚拟路由并在用户没有意识到的情况下快速返回到目标路由。


当我使用 '/' 而不是 '/DummyComponent' 时,它就像一个魅力
在 Angular 7 中运行良好,浏览器历史记录没有问题。由于针对特定组件,我选择使用此解决方案。在我看来,重新加载同一个页面通常是一种异常情况,因此让整个应用程序遵循特定的范式似乎有点矫枉过正。这比其他解决方案更小且更容易实现。
好的,它可以工作,但是......它将重新加载您的 HomeComponent(或您在路线“/”上拥有的任何东西),将毫无意义地经历 ngOnInit/ngOnDestroy 的整个生命周期。最好有一个带有一些虚拟和轻量级组件的特定路线,否则您会注意到滞后
如果您想刷新“/”页面,这不会解决。在该实例中,您需要导航到另一个页面(我遇到了这个问题)。有人建议创建一个虚拟页面,我认为如果您希望此解决方案能够干净地工作,这是一个好主意。就我而言,我选择了顶级解决方案,但似乎这也是一个可行的快速而肮脏的解决方案。
这是最好的答案。我最终制作了一个 /dummy 组件并为它添加了一条路线,然后一切都在 Angular 10 上完美运行。
T
The Red Pea

现在可以使用路由器配置的 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],
 })

在您的路由定义中,将 runGuardsAndResolvers 设置为 always。这将告诉路由器始终启动警卫和解析器循环,触发相关事件。

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 函数,
我不这么认为...除非您离开路线并再次返回。初始化函数并不是世界末日,您可以控制初始化,使其与重新加载组件具有相同的效果。您是否有任何特殊原因要在没有 init 的情况下进行完全重新加载?
我已经为我的问题找到了解决方案,感谢您的回复和有用的博客。
除了窗口重新加载之外,如何在 Angular 4 中执行此操作。
如果我在所有页面中都需要这种行为怎么办?有没有办法开发标准行为,以便在导航相同的 url 时重新加载所有页面(调用 ionWillEnter),而不必处理每个页面组件上的事件?
A
Andris

我将这个用于 Angular 11 项目:

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

PS:经过测试并适用于 7 以上的所有版本。


我想我会谈谈我对这个解决方案的经验。对我来说,它似乎重新加载了与路由关联的整个组件。在我的情况下,具有不同路由参数的常规 router.navigate 将保持组件加载并仅从 ngOnInit 加载新更改(基于路由参数)。您的解决方案似乎没有这样做,它似乎实际上重新加载了整个组件,然后根据路由参数在 ngOnInit 中对其进行更改。无论如何,在我的情况下,这对我来说是一个小小的不便,您的解决方案可以满足我的需求。
我的目的的最佳答案+1
这似乎对我不起作用。我的情况是我想在离开应用程序状态时重新加载,因此我将其包裹在 if 中以检查应用程序的先前状态。如果这是真的,我们处于“其他”状态但不再存在,则状态标志被重置并且此代码运行,但没有任何反应。我使用了 window.location.reload();,但这似乎是一种更暴力的方法。该线程中的其他建议均未奏效。
A
Arg0n

编辑

对于较新版本的 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 和数据。

Link to original GitHub feature request

归功于 GitHub 上的 mihaicux2。

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


刚刚在 Angular 4.4.x 中尝试过,这完全有效。谢谢!
这对我来说非常有用,直到我实现了 Material 的 nav-tab-bar 来导航我的应用程序中每个父路由的子路由。一旦用户点击运行此代码的页面,动画墨水条就会消失。 (为什么?我没有足够的时间和空间来解释......)
这是一个非常糟糕的主意——你的 ActivatedRoute 现在总是一样的。
@AnandTyagi 如果您使用的是 Angular 5.1+,请尝试 SimonMcClives 解决方案。也许这对你更有效。
非常糟糕的主意......因为一旦它应用了 routeReuseStrategy.shouldReuseRoute = false,那么它将加载组件层次结构的每个组件。因此,这意味着您的每个父子组件都会在任何 url 更改时开始重新加载。那么使用这个框架就没有任何意义了。
Y
Yakov Fain

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


现在你说我必须同意但是...... angularjs ui路由器有一个重新加载选项,因此重新加载路由是有意见的;-)但是是的,我可以为那个提示做一个重新加载数据,这实际上很明显......
我不同意如果你想重新运行警卫,比如有人注销怎么办?
@YakovFain 抱歉,但这是错误的。这意味着您现在有两个路由行为的真实来源 - 一个发生在警卫期间,另一个发生在组件中。您现在不仅可能会重复逻辑,而且还与更自然的数据流背道而驰:1. 对 API 进行更改,2. 刷新路由以从 API 获取新的数据状态,使 API 成为事实来源。根本没有理由不让用户手动重新触发路由,以便数据的自然流动可以再次发生。
我不认为这是一个好的答案。路由器应该是您数据的真实来源。如果您必须通过单独的服务重新加载它,那么路由器将不再知道最新版本,您的组件将不再依赖您的路由器作为事实来源。
如果您有多个路由到同一个组件,则此解决方案也存在问题。当它最终转到同一个组件时更改路由不会重新加载。
W
Wlada

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

当您需要重新加载时,您需要调用它。

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

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

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

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

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

这是正确的答案。 “onSameUrlNavigation”从 Angular 5 开始工作。请投票将其移至顶部
这对我不起作用。安德里斯的下面做了。尽管 Andris 的重新加载并不像实际的常规路线导航那样“干净”。它似乎并没有重新加载整个页面,但似乎确实重新加载了与路由关联的整个组件。我只需要根据路由参数重新加载子组件,而不是与路由关联的整个组件。无论如何,它工作得很好。只是想我会附和我的经验。
最后一段代码解决了我的问题。设置 runGuardsAndResolvers: 'always' 会强制应用程序使用警卫,因此重复调用那里存在的 API。感谢@Wlada
N
Nitin Kamate

这对我来说就像一个魅力

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

这是最简单的答案。如果可以的话,我会将其标记为已接受的答案。与公认的答案相反,在某些情况下,您可能需要重新加载页面上使用的每个组件,并且必须单独重新加载每个组件,这些组件可能位于不同的路径,即使通过服务也是过大的。
似乎对我不起作用。我期待这会再次重新触发 ngOnInit 函数。显然它没有..或者我错过了什么?
如果您已经在同一路线中,则不会触发 ngOnInit 函数。如果您需要调用它,您可以手动调用它作为上述代码的第三行。
n
newari

小技巧:使用相同的路径和一些虚拟参数。例如-

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

现在:this.router.navigate(['/pocetna'], { queryParams: { 'refresh': 1 } });route.queryParams.subscribe(val => myRefreshMethod()),其中 route: ActivatedRoute 被注入到刷新的组件中......希望它有所帮助
目前在 Angular 7 中,这似乎不再起作用。任何人都可以确认,还是我做错了什么? (我也尝试了 insan-e 的细微变化。)
可能有点丑
i
indreed

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

小心这种方法,这将全局影响路由器的行为(在子路由之间导航时,父路由总是会重新加载)。
k
karthi

在参数更改重新加载页面不会发生。这真是一个很好的功能。无需重新加载页面,但我们应该更改组件的值。 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) {

}

V
Vlad

对我来说,使用硬编码

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

不建议!人们在整个 SO 中不断以不同的方式重新发布此解决方案。是的,它可能会解决您当前的问题,但是您稍后会忘记您已实现此功能,并且您将花费数小时试图找出您的应用程序出现奇怪行为的原因。
如果您必须使用此功能,请使用 Ebraheem Alrabee 的解决方案,并且仅将其应用于单个路线。
C
Carli Beeli

找到了一个快速直接的解决方案,不需要修改 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>

希望能帮助到你 :)


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

@angular/router 导入 RouterActivatedRoute

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

如果您使用虚拟路由,那么如果您实现了未找到的 url,以防与任何 url 不匹配,您将看到标题闪烁“未找到”。


先生,你是谁,在 Angular 方面如此聪明
E
Evgeny Nozdrev

解决方案:

订阅 URL 参数并在那里初始化组件。没有技巧,只是“新 URL --> 新数据”,包括第一次加载。

对于 URL 参数(如 /persons/:id):

constructor(protected activeRoute: ActivatedRoute, ...) {
    this.activeRoute.paramMap.subscribe(paramMap => {
        const id = paramMap.get('id');    // get param from dictonary
        this.load(id);                    // load your data
    });
}

对于 URL 查询参数(如 ?q=...&returnUrl=...)(通常不需要):

    this.activeRoute.queryParamMap.subscribe(queryParamMap => {
        const returnUrl = queryParamMap.get('returnUrl');
        ...
    });

问题的原因是:

当 URL 发生变化时,Angular 将尽可能重用旧组件以节省计算机资源。加载数据是您的自定义代码,因此 Angular 无法为您完成。


请注意,id 被读取为字符串,因为整个 URL 都是字符串。使用 new Guid(id) 将字符串转换为 Guid。或者,如果 URL 中不存在 id,甚至使用 new Guid(id || Guid.empty) 来获得 zeros-Guid。
拯救了我的一天。谢谢老哥的回答
D
Dzmitry Vasilevsky

有点硬核但是

this.router.onSameUrlNavigation = 'reload';
this.router.navigateByUrl(this.router.url).then(() => {

    this.router.onSameUrlNavigation = 'ignore';

});

E
Evandro Mendes

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

看一个例子:

export class Component implements OnInit {

  constructor() {   }

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

  ngOnInit () {

  }

s
sabithpocker

通过为 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 {}

要使用它,我们只需要将 reload 添加到我们想要去的 url 中:

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

l
losciur

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

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

T
Trafalgar

有不同的方法来刷新当前的路线

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

然后,您可以通过订阅路由来处理它们

您可以将它与 runGuardsAndResolvers 组合使用以重新运行解析器

保持路由器不动

使用 URL 中的当前时间戳传递刷新 queryParam 并订阅路由组件中的 queryParams。

使用 router-outlet 的 activate 事件来获取路由组件。

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

希望这可以帮助。


B
Beyazid

我正在使用 setTimeoutnavigationByUrl 来解决这个问题......而且它对我来说工作正常。

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

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

D
Dan King

非常令人沮丧的是,Angular still 似乎没有为此提供一个好的解决方案。我在这里提出了一个 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));
  }
}

J
Jeremy Caney

编写一个函数——例如,reloadCurrentPage。由于 window 是一个可以在 Angular 组件中直接重用的全局对象,因此 window.location.reload() 会重新加载当前活动页面。

function reloadCurrentPage() {
    window.location.reload();
}

A
Anton Zimm

就我而言:

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

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

工作正确


E
Ebraheem Alrabeea

假设你要刷新的组件的路由是 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" 后的确切路线。


X
Xiaodi HU

使用“时间戳”是一种廉价而神奇的方式。

this.router.navigate([], {
    relativeTo: this.route,
    queryParams: {
        ...this.route.snapshot.queryParams,
        // replace 't' with any others not to conflict with exsiting
        // '2^11' prevents reloading in about 2 seconds
        t: Date.now() >> 11, 
        skipLocationChange: true,
    },
});

O
Omar

订阅路由参数更改

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

O
Omkar Joshi

如果您通过路由器链接更改路由,请按照以下步骤操作:

  constructor(public routerNavigate: Router){

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

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

            if (evt instanceof NavigationEnd) {

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

S
Syed mohamed aladeen

下面的代码将起作用:

logoFn(url: any) {

    this.router.routeReuseStrategy.shouldReuseRoute = function () {
        return false;
    };
    this.router.navigate(['']); or
    this.router.navigate([url]);

}

m
mbao01

我相信这已经在 Angular 6+ 中(本地)解决了;查看

这里 https://github.com/angular/angular/issues/13831 &&

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

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

如果您想定位单个组件,方法如下: 使用更改的查询参数,以便您可以根据需要多次导航。

在导航点(类)

   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

有趣的是,这种方法只能工作 一次 - Angular 中似乎存在一个错误,即 queryParamsMap 主题仅在第一次更新,但在任何后续更新中都没有。
B
Basel Issmail

决定何时应该存储路由返回 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;
    }
});