57

I have a page for editing user, it has some children components inside. Each children components can change or doing some effect to its parent component.

So instead of emitting the changes to parent and updating some fields, I did a "reload" of the current page with

private route: ActivatedRoute;

reload(){
    this.router.navigate(["/admin/user/edit/"+this.user.id]);
}

Basically, it redirects to the current page. For example, the current page is http://web.info/admin/user/edit/9 it will be redirected to this page with the hope all the data inside that page reloaded with the newest data.

but it seems the angular won't redirect/reload the same page with the router.navigate

How I should reload a current page?

Edit:

Here is the reason why I need to reload the page instead of manually updating the data on the current page. I need to do updates on Other Component, when I did the update it will add something to History Component. I need to refresh the User Component and History Component together since both components affected by the changes in Other Component.

Components

Liam
  • 27,717
  • 28
  • 128
  • 190
nightingale2k1
  • 10,095
  • 15
  • 70
  • 96
  • Look here: https://github.com/angular/angular/issues/13340 You could use simply `window.location.href = '...';` – Jacopo Sciampi Sep 18 '18 at 14:57
  • 1
    i tried using window.location.href = this.router.url .. it works but it doesn't look natural / similiar with other page. I will use this as last resort – nightingale2k1 Sep 18 '18 at 15:16
  • I found a better way than reload the page. instead i will reload the data that just got updated. this way faster n better – nightingale2k1 Jul 23 '19 at 05:42

16 Answers16

77

A little bit tricky to do something so simple but had no luck trying to reload and recreate the entire parent & child components with current solution.

Angular Router now provides strategy configuration to tell the Router what to do in case you navigate to the same URL as this user suggests in this GitHub issue.

First of all you can configure what to do while setting up the Router (your router module).

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

Or, if you are like me and don't want to change the entire router module behaviour you can do it with a method/function like this:

reloadComponent() {
    this._router.routeReuseStrategy.shouldReuseRoute = () => false;
    this._router.onSameUrlNavigation = 'reload';
    this._router.navigate(['/same-route']);
}

Of course you have to first inject Router in your component's constructor:

// import { Router } from '@angular/router';
...
constructor(private _router: Router){}
...

Somehow and as pointed out by @Abhiz you have to set shouldReuseRoute, with just configuring the Router by itself the page reload doesn't work with this aproach.

I've used an arrow function for shouldReuseRoutebecause new TSLint rules won't allow non-arrow functions.

Daniel Díaz Astudillo
  • 1,622
  • 2
  • 14
  • 14
  • 2
    Thanks, the second approach (not changing entire router behavior) works great on Angular 8. – sofly Sep 10 '19 at 21:35
  • 1
    would it affect on another routing? or will be destroyed within these changed properties and will not affect to another routers in the project? – Igor Kurkov Jul 14 '20 at 10:48
  • 1
    The second method actually affects other routers if you use injection. In my scenario, one of the components uses linear stepper. By changing the strategy, that component went to infinite reload. I finally go with "this.router.navigateByUrl('/', {skipLocationChange: true}).then(() => this.router.navigate(['YourCurrentRoute', this.id])); – Shengfeng Li Jul 29 '20 at 21:11
  • Second Approach works perfectly for Angular 7 also we can have like this to preseve queryparams also this.router.navigate(['./'], { relativeTo: this.activatedRoute, queryParamsHandling: 'preserve' }); – Kishore Kumar Mar 03 '21 at 16:38
  • I made it work without this._router.onSameUrlNavigation = 'reload'; – Rom1 Sep 03 '21 at 14:14
35

It will work 100%. The following lines of code are responsible for page reload in my project.

load(val) {
if (val == this.router.url) {
  this.spinnerService.show();
  this.router.routeReuseStrategy.shouldReuseRoute = function () {
    return false;
  };
 }
}

Just use the following part in your code.

this.router.routeReuseStrategy.shouldReuseRoute = function () {
    return false;
  };
Abhiz
  • 970
  • 1
  • 16
  • 36
  • am using Angular 9 and this does nothing for me. window.location.reload() works but its a clunk. – Darren Street Jul 06 '20 at 09:41
  • 1
    Complete solution needs additional step:`this.router.onSameUrlNavigation = 'reload';` But if you need to reload the page only in specific scenarios, you need to save router state, change to this, make reload and restore state to default. – Alexander Aug 28 '20 at 16:54
  • This worked perfectly fine for my usecase. Used the 2 liner at the end after using `this.router.navigateByUrl("someUrl")`. – Philipp Doerner Nov 10 '20 at 18:12
34

This is the most simple solution if you just need to refresh the entire page

   refreshPage() {
    window.location.reload();
   }
brian
  • 664
  • 6
  • 8
23

Without specifying the path you can do:

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

reload() {
  this.router.routeReuseStrategy.shouldReuseRoute = () => false;
  this.router.onSameUrlNavigation = 'reload';
  this.router.navigate(['./'], { relativeTo: this.route });
}

And if you use query params you can do:

reload() {
  ...
  this.router.navigate(['./'], { relativeTo: this.route, queryParamsHandling: 'preserve' });
}
iemi111
  • 231
  • 2
  • 4
6
import { DOCUMENT } from '@angular/common';
import { Component, Inject } from '@angular/core';

@Component({
  selector: 'app-refresh-banner-notification',
  templateUrl: './refresh-banner-notification.component.html',
  styleUrls: ['./refresh-banner-notification.component.scss']
})

export class RefreshBannerNotificationComponent {

  constructor(
    @Inject(DOCUMENT) private _document: Document
  ) {}

  refreshPage() {
    this._document.defaultView.location.reload();
  }
}
Crystal
  • 1,425
  • 1
  • 22
  • 34
6

I have solved by this way

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

constructor(private router: Router
          , private activeRoute: ActivatedRoute) {

}
reloadCurrentPage(){
   let currentUrl = this.router.url;
   this.router.navigateByUrl('/', {skipLocationChange: true}).then(() => {
   this.router.navigate([currentUrl]);
   });
 }
Khairul Alam
  • 1,266
  • 2
  • 11
  • 31
4

Writing this as 2021 (Angular 12 running). Read explanation or jump to end for straight answer.

All the answers on this thread and others didn't help me quite much because of unwanted behaviour. What I did instead is implemented a hack.

Some light on existing answers

Angular will reload page which means Page Component/Resolvers/Guards in specific way.

using this.router.onSameUrlNavigation = 'reload';

doesn't work most of the time because main purpose of it is to Re-enable Resolvers/Guards. Its mistaken for other meaning though.Also I didn't want to change this across as a global setting so nope!

Another way of window.location.reload() OR window.location.href=window.location.href is worst possible way as it violates SPA rules. Downloading all chunks again is very bad solution.

While below solution works, for my usecase it was routing twice, so dropped this as well

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

Now the HACK / Solution

Why not tell angular its different route altogether, so reloading is taken care by Angular itself, it also covers guards, resolvers everything. For my usecase

In app-routing.module.ts I added same module with two different routes

one with '' empty route and one with say 'post-login'

  {
    path: '',
    loadChildren: () => import('./post-login/post-login.module').then((m) => m.PostLoginModule),
    canActivate: [AuthGuard],
  },
  {
    path: 'post-login',
    loadChildren: () => import('./post-login/post-login.module').then((m) => m.PostLoginModule),
    canActivate: [AuthGuard],
  }

Now inside wherever I want to reload the same page, Inject router: Router

and use simply like this

 this.router.navigateByUrl(this.router.url.includes('post-login') ? '' : 'post-login');

This reloads page with alternate additional 'post-login' in Url but its fine for my usecase. Hope it helps :)

minigeek
  • 2,766
  • 1
  • 25
  • 35
3

Because it's the same component. You can either listen to route change by injecting the ActivatedRoute and reacting to changes of params and query params, or you can change the default RouteReuseStrategy, so that a component will be destroyed and re-rendered when the URL changes instead of re-used.

Lazar Ljubenović
  • 18,976
  • 10
  • 56
  • 91
2

With angular 11 you can just use this:

in route config add runGuardsAndResolvers: 'always'

const routes: Routes = [
  { path: '', component: Component, runGuardsAndResolvers: 'always' },
];

and this is your method to reload:

  reloadView(): void {
    this.router.navigated = false;
    this.router.navigate(['./'], { relativeTo: this.route });
  }

this will trigger any resolver on that config

spiotr12
  • 79
  • 6
  • `this.router.navigated = false;` was what I was missing to get `runGuardsAndResolvers: 'always'` working as expected. – Thomas May 03 '21 at 14:40
2

By this way we can preserve queryparams also

 onReloadPage() {
     this.router.routeReuseStrategy.shouldReuseRoute = () => false;
     this.router.onSameUrlNavigation = 'reload';
     this.router.navigate(['./'], { relativeTo: this.activatedRoute, queryParamsHandling: 'preserve' });
 }
Kishore Kumar
  • 174
  • 2
  • 14
1

Setting shouldReuseRoute and onSameUrlNavigation properly on the router will force angular to reload when navigating on the same page, however as the router is a singleton, it might be relevant to set back its initial values after reloading the page.

This method below will backup and restore the router's settings to prevent side effects to occur. Please comment if you do have a cleaner solution to achieve the same.

class MyComponent {

constructor(private router: Router){}

public async reload(): Promise<boolean> {
    const router = this.router;
    const routeReuseStrategy = router.routeReuseStrategy.shouldReuseRoute;
    const onSameUrlNavigation = router.onSameUrlNavigation;
    try {
      router.routeReuseStrategy.shouldReuseRoute = () => false;
      router.onSameUrlNavigation = 'reload';
      return await router.navigateByUrl(router.url);
    } finally {
      router.routeReuseStrategy.shouldReuseRoute = routeReuseStrategy;
      router.onSameUrlNavigation = onSameUrlNavigation;
    }
  }
}
Flavien Volken
  • 19,196
  • 12
  • 100
  • 133
1

For child and main component, I have written the following code to reload the page

reloadCurrentRoute() {
    let currentUrl = this.router.url;
    this.router.navigateByUrl('/', {skipLocationChange: true}).then(() => {
        this.router.navigate([currentUrl]);
    });
}
Syscall
  • 19,327
  • 10
  • 37
  • 52
sourcecode
  • 4,116
  • 1
  • 20
  • 14
0

Here is the simple one

if (this.router && this.router.url === '/') { or your current page url e.g '/home' 
    window.location.reload();
  } else {
    this.router.navigate([url]);
  }
0

I believe Angular 6 has the BehaviorSubject object. My sample below is done using Angular 8 and will hopefully work for Angular 6 as well.

This method is a more "reactive" approach to the problem, and assumes you are using and are well versed in rxjs.

Assuming you are using an Observable in your parent component, the component that is used in your routing definition, then you should be able to just pulse the data stream pretty easily.

My example also assumes you are using a view model in your component like so...

vm$: Observable<IViewModel>;

And in the HTML like so...

<div *ngIf="(vm$ | async) as vm">

In your component file, add a BehaviorSubject instance...

private refreshBs: BehaviorSubject<number> = new BehaviorSubject<number>(0);

Then also add an action that can be invoked by a UI element...

  refresh() {
    this.refreshBs.next(1);
  }

Here's the UI snippet, a Material Bootstrap button...

<button mdbBtn color="primary" class="ml-1 waves-dark" type="button" outline="true"
                    (click)="refresh()" mdbWavesEffect>Refresh</button>

Then, in your ngOnIt function do something like this, keep in mind that my example is simplified a bit so that I don't have to provide a lot of code...

  ngOnInit() {

    this.vm$ = this.refreshBs.asObservable().pipe(
      switchMap(v => this.route.queryParamMap),
      map(qpm => qpm.get("value")),
      tap(v => console.log(`query param value: "${v}"`)),

      // simulate data load
      switchMap(v => of(v).pipe(
        delay(500),
        map(v => ({ items: [] }))
      )),
      
      catchError(e => of({ items: [], error: e }))
    );
    
  }
Dharman
  • 30,962
  • 25
  • 85
  • 135
Jeff Marino
  • 1,156
  • 1
  • 7
  • 7
0

See this stackblitz which use a RouteReuseStrategy in combination with the onSameUrlNavigation: 'reload' Router option.

This strategy ensures that angular will always re-render the components when navigating to what it considers the "same" route (which includes having different path and query parameters).

@Injectable()
export class MyStrategy extends RouteReuseStrategy {
   shouldDetach(route: ActivatedRouteSnapshot): boolean {
    return false;
  }
  store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void {}
  shouldAttach(route: ActivatedRouteSnapshot): boolean {
    return false;
  }
  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle|null {
    return null;
  }
  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    return false;
  }
}

const routes = [
  {path: '2', component: Empty2},
  {path: '', component: Empty},
];

@NgModule({
  imports:      [ BrowserModule, RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload'}) ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ], 
  providers: [{provide: RouteReuseStrategy, useClass: MyStrategy}]
})
export class AppModule { }
jenson-button-event
  • 18,101
  • 11
  • 89
  • 155
-6
private router: Router

this.router.navigateByUrl(url)

It will redirect to any pages without data lost (even current page). Data will remain as is.

franiis
  • 1,378
  • 1
  • 18
  • 33