nightingale2k1
nightingale2k1

Reputation: 10315

How to reload current page?

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

Upvotes: 58

Views: 196835

Answers (16)

sourcecode
sourcecode

Reputation: 4601

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

Upvotes: 2

minigeek
minigeek

Reputation: 3166

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 :)

Upvotes: 4

Flavien Volken
Flavien Volken

Reputation: 21259

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

Upvotes: 1

Khairul Alam
Khairul Alam

Reputation: 1336

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

Upvotes: 8

Kishore Kumar
Kishore Kumar

Reputation: 184

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

Upvotes: 2

jenson-button-event
jenson-button-event

Reputation: 18941

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

Upvotes: 0

spiotr12
spiotr12

Reputation: 79

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

Upvotes: 2

Jeff Marino
Jeff Marino

Reputation: 1166

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

Upvotes: 0

iemi111
iemi111

Reputation: 231

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

Upvotes: 23

Bharat chaudhari
Bharat chaudhari

Reputation: 534

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

Upvotes: 0

brian
brian

Reputation: 692

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

   refreshPage() {
    window.location.reload();
   }

Upvotes: 33

Crystal
Crystal

Reputation: 1505

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

Upvotes: 6

Abhiz
Abhiz

Reputation: 1030

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

Upvotes: 35

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.

Upvotes: 77

Jegatheepan
Jegatheepan

Reputation: 1

private router: Router

this.router.navigateByUrl(url)

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

Upvotes: -6

Lazar Ljubenović
Lazar Ljubenović

Reputation: 19754

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.

Upvotes: 3

Related Questions