ChatGPT解决这个技术问题 Extra ChatGPT

How to reload the current route with the angular 2 router

I am using angular 2 with hashlocation strategy.

The component is loaded with that route:

"departments/:id/employees"

So far fine.

After I do a successful batch save of multiple edited table rows I want to reload the current route URL via:

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

But nothing happens, why?

Take a look at this answer to a similar question: stackoverflow.com/a/44580036/550975
Solution: subscribe to query params and load data from there. No tricks, just "URL changed --> data reloaded" (including first time). More: stackoverflow.com/a/68503542/7573844
Cause: Angular reuse component if possible to save computer's resources. Loading of data is your custom logic, Angular can't do it for you.

G
Ganesh

Create a function in the controller that redirects to the expected route like so

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

then use it like this

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

this function will redirect to a dummy route and quickly return to the destination route without the user realizing it.


it works like a charm when i used '/' instead of '/DummyComponent'
Works fine in Angular 7, without problems in the browser history. I opted to use this solution due to being targeted to a specific component. It seems to me that reloading the same page is generally an abnormal case, so making the entire application follow a specific paradigm seems like overkill. This is small and easier to implement than other solutions.
Okay it works but... it will reload your HomeComponent (or whatever you have on the route "/"), will go throught the full lifecycle of ngOnInit/ngOnDestroy for nothing. Better to have a specific route with some dummy and lightweight component or you will notice the lag
This does not address if you want to refresh the '/' page. You'd need to navigate to another page in that instance (I ran into this issue). Someone suggested creating a dummy page, I think that's a good idea if you want this solution to work cleanly. In my case, I opted for the top solution, but it appeared that this also was a quick and dirty solution that would work.
This is the best answer. I ended up making a /dummy component and added a route for it, and then everything worked perfectly on Angular 10.
T
The Red Pea

This can now be done in Angular 5.1 using the onSameUrlNavigation property of the Router config.

I have added a blog explaining how here but the gist of it is as follows

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

In your router config enable onSameUrlNavigation option, setting it to 'reload'. This causes the Router to fire an events cycle when you try to navigate to a route that is active already.

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

In your route definitions, set runGuardsAndResolvers to always. This will tell the router to always kick off the guards and resolvers cycles, firing associated events.

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

Finally, in each component that you would like to enable reloading, you need to handle the events. This can be done by importing the router, binding onto the events and invoking an initialisation method that resets the state of your component and re-fetches data if required.

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

With all of these steps in place, you should have route reloading enabled.


Is there a way to reload the component instead of calling an init function,
I don't think so... unless you navigate away from the route and back again. An init function isn't the end of the world, you can control the initialisation to the point that it has the same effect as reloading the component. Is there any particular reason you want to do a full reload without init?
I have figured out a solution for my problem,Thank you for your response and the blog it was useful.
How to do it in Angular 4 other than window reload.
What if I need this behavior in all pages? Is there a way to develop a standard behavior so that all pages are reloading (calling ionWillEnter) when navigating same url without having to handle events on each page component?
A
Andris

I am using this one for Angular 11 project:

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

PS: Tested and works on all versions above 7.


I thought I'd chime in on my experience with this solution. For me, it seems to reload the entire component associated with the route. In my situation a regular router.navigate with different routing params will keep the component loaded and just load the new changes from ngOnInit (based on route params). Your solution doesn't seem to do this, it seems to actually reload the entire component and then make it's changes in the ngOnInit based on route params. Anyhow, it's a minor inconvenience for me in my situation and your solution works for my needs.
Best answer for my purpose +1
This doesn't seem to work for me. My situation is I want to reload on leaving an app state, so I have this wrapped in an if to check the previous state of the app. If it's true we were in the "other" state but are no longer there, the state flag is reset and this code runs, but nothing happens. I've used window.location.reload();, but that seems to be a much more brute force approach. None of the other suggestions in this thread have worked either.
A
Arg0n

EDIT

For newer versions of Angular (5.1+) use answer suggested by @Simon McClive

Old answer

I found this workaround on a GitHub feature request for Angular:

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

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

I tried adding this to my app.component.ts ngOnInit function, and it sure worked. All further clicks on the same link now reloads the component and data.

Link to original GitHub feature request

Credit goes to mihaicux2 on GitHub.

I tested this on version 4.0.0-rc.3 with import { Router, NavigationEnd } from '@angular/router';


Just tried this in Angular 4.4.x and this completely works. Thanks!
This was working great for me, until I implemented Material's nav-tab-bar for navigating through the children routes of each parent route in my app. Once the user hits the page that runs this code, the animated ink bar will disappear. (Why? I don't have enough time or space to explain...)
This is a very bad idea — your ActivatedRoute now will always be the same.
@AnandTyagi Try SimonMcClives solution if you're on Angular 5.1+. Maybe that works better for you.
Very bad idea... Because once it applied routeReuseStrategy.shouldReuseRoute = false, then it will load every component of component hierarchy. So it mean your every parent and child component starts reload on any url changes. So then there is no meaning of using this framework.
Y
Yakov Fain

If your navigate() doesn't change the URL that already shown on the address bar of your browser, the router has nothing to do. It's not the router's job to refresh the data. If you want to refresh the data, create a service injected into the component and invoke the load function on the service. If the new data will be retrieved, it'll update the view via bindings.


Now you say it I must agree BUT... the angularjs ui router had a reload option thus reloading a route is opiniated ;-) But yeah I could just do a reload data thx for that tip which is actually obvious...
I don't agree what if you want to rerun the guards, say if someone logs out?
@YakovFain sorry, but this is false. This means you now have two sources of truth for the route behavior - one happens during the guard, the other happens in the component. Not only are you now potentially duplicating logic, you are bucking against a more natural data flow: 1. make changes to API, 2. refresh the route to fetch the new state of data from the API, making the API the source of truth. There is simply not reason NOT to give users the ability to manually re-trigger a route so that the natural flow of data can happen again.
I don't think this is a good answer. The router should be the source of truth for your data. If you have to reload it via a separate service, then the router no longer knows about the latest version and your components can no longer rely on your router as the source of truth.
There's also problem with this solution if you have multiple routes to the same component. Changing a route when it ends up going to the same component doesn't reload.
W
Wlada

This is what I did with Angular 9. I'm not sure does this works in older versions.

You will need to call this when you need to reload.

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

Router forRoot needs to have SameUrlNavigation set to 'reload'

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

And your every route needs to have runGuardsAndResolvers set to 'always'

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

This is the correct answer. "onSameUrlNavigation" works since Angular 5. Please upvote to move it to the top
This didn't work for me. Andris's below did. Although Andris's reloading isn't as 'clean' as an actual regular route navigation. It doesn't seem to reload the entire page, but it does seem to reload the entire component associated with the route. I just needed child components to reload based on route parameters, not the entire component associated with the route. Anyhow, it works well enough. Just thought I'd chime in on my experience.
My issue was solved by the last bit of code. Setting runGuardsAndResolvers: 'always' forced the app to use the guard therefore repeating the call to the API that existed there. Thanks for that @Wlada
N
Nitin Kamate

This works for me like a charm

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

This is the simplest answer. I would mark this as the accepted answer if I could. Contrary to the accepted answer, there may be situations where you need to reload every single component used on a page and to have to individually reload each one, which may be at different routes, would be overkill even via a service.
Doesn't seem to work for me. I was expecting that this would re-trigger the ngOnInit function again. Apparently it doesn't.. Or m i missing smthing ?
ngOnInit function will not be triggered if you are in the same route already. If you need that to be called, you can call it manually as a third line to the code mentioned above.
n
newari

Little tricky: use same path with some dummy params. For example-

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

Now: this.router.navigate(['/pocetna'], { queryParams: { 'refresh': 1 } }); and route.queryParams.subscribe(val => myRefreshMethod()) where route: ActivatedRoute is injected in refreshed component... Hope it helps
Presently in Angular 7 this doesn't appear to work any more. Can anyone confirm, or am I doing something wrong? (I tried insan-e's slight variation too.)
A little ugly maybe.
i
indreed

Angular 2-4 route reload hack

For me, using this method inside a root component (component, which is present on any route) works:

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

Be careful with this approach, this will globally affect router behavior (parent route will always reload when navigating between child routes).
k
karthi

On param change reload page won't happen. This is really good feature. There is no need to reload the page but we should change the value of the component. paramChange method will call on url change. So we can update the component data

/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

For me works hardcoding with

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

Not recommended! People keep re-posting this solution in different ways throughout this SO. Yes it may fix your immediate issue but you are going to forget later that you implemented this and you'll be spending hours trying to find out why your app is experiencing weird behavior.
If you must use this use Ebraheem Alrabee' solution and only apply it to a single route.
C
Carli Beeli

Found a quick and straight-forward solution that doesn't require to tinker with the inner workings of angular:

Basically: Just create an alternate route with the same destination module and just toggle between them:

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

And here the toggeling menu:

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

Hope it helps :)


What if the alternate route has parameter and you want to re-load when parameter changes?
A
Aamer Shahzad

Import Router and ActivatedRoute from @angular/router

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

Inject Router and ActivatedRoute (in case you need anything from the URL)

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

Get any parameter if needed from URL.

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

Using a trick by navigating to a dummy or main url then to the actual url will refresh the component.

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

In your case

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

If you use a dummy route then you will see a title blink 'Not Found' if you have implemented a not found url in case does not match any url.


who art thou sir who are so wise in ways of Angular
E
Evgeny Nozdrev

Solution:

Subscribe to URL params and initialize component there. No tricks, just "new URL --> new data", including first time loading.

For URL params (like /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
    });
}

For URL query params (like ?q=...&returnUrl=...) (usually not required):

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

Problem's cause is:

When URL changes, Angular will reuse old component if possible to save computer's resources. Loading of data is your custom code, so that Angular can't do it for you.


Note that id is read as string since whole URL is a string. Use new Guid(id) to convert a string to Guid. Or even use new Guid(id || Guid.empty) to has zeros-Guid if id not present in URL.
Saved my day. Thanks for the answer bro
D
Dzmitry Vasilevsky

A little bit hardcore but

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

    this.router.onSameUrlNavigation = 'ignore';

});

E
Evandro Mendes

implement OnInit and call ngOnInit() in method for route.navigate()

See an example :

export class Component implements OnInit {

  constructor() {   }

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

  ngOnInit () {

  }

s
sabithpocker

Solved a similar scenario by using a dummy component and route for reload, which actually does a redirect. This definitely doesn't cover all user scenarios but just worked for my scenario.

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

The routing is wired to catch all urls using a wildcard:

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 {}

To use this, we just need to add reload to the url where we want to go:

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

l
losciur

A solution is to pass a dummy parameter (i.e. the time in seconds), in this way the link is always reloaded:

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

T
Trafalgar

There are different approaches to refresh the current route

Change router behaviour (Since Angular 5.1) Set the routers onSameUrlNavigation to 'reload'. This will emit the router events on same URL Navigation.

You can then handle them by subscribing to a route

You can use it with the combination of runGuardsAndResolvers to rerun resolvers

Leave the router untouched

Pass a refresh queryParam with the current timestamp in the URL and subscribe to queryParams in your routed component.

Use the activate Event of the router-outlet to get a hold of the routed component.

I have written a more detailed explanation under https://medium.com/@kevinkreuzer/refresh-current-route-in-angular-512a19d58f6e

Hope this helps.


B
Beyazid

I am using setTimeout and navigationByUrl to solve this issue... And it is working fine for me.

It is redirected to other URL and instead comes again in the current URL...

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

D
Dan King

Very frustrating that Angular still doesn't seem to include a good solution for this. I have raised a github issue here: https://github.com/angular/angular/issues/31843

In the meantime, this is my workaround. It builds on some of the other solutions suggested above, but I think it's a little more robust. It involves wrapping the Router service in a "ReloadRouter", which takes care of the reload functionality and also adds a RELOAD_PLACEHOLDER to the core router configuration. This is used for the interim navigation and avoids triggering any other routes (or guards).

Note: Only use the ReloadRouter in those cases when you want the reload functionality. Use the normal Router otherwise.

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

Write a function—e.g., reloadCurrentPage. As window is a global object which can be reused directly in Angular components, window.location.reload() reloads the currently active page.

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

A
Anton Zimm

In my case:

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

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

work correct


E
Ebraheem Alrabeea

Suppose that the component's route you want to refresh is view, then use this:

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

you can add a debugger inside the method to know what is the exact route will come after navigate to "departments/:id/employees".


X
Xiaodi HU

using 'timestamp' is a cheap and amazing way.

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

subscribe to route parameter changes

    // 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

If you are changing route via Router Link Follow this:

  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

This below code will work:

logoFn(url: any) {

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

}

m
mbao01

I believe this has been solved (natively) in Angular 6+; check

here https://github.com/angular/angular/issues/13831 &&

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

But this works for an entire route (includes all children routes as well)

If you want to target a single component, here's how: Use a query param that changes, so you can navigate as many times as you want.

At the point of navigation (class)

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

In Component that you want to "refresh/reload"

// . . . 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

Interestingly, this approach will only work once - it seems there's a bug in Angular where the queryParamsMap subject only gets updated the first time, but not on any subsequent updates.
B
Basel Issmail

Decides when the route should be stored return false to

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

and set the navigated value of router to false, that show that this route never routed

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