Reputation: 10315
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.
Upvotes: 58
Views: 196835
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
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
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
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
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
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
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
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
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
Reputation: 534
if (this.router && this.router.url === '/') { or your current page url e.g '/home'
window.location.reload();
} else {
this.router.navigate([url]);
}
Upvotes: 0
Reputation: 692
This is the most simple solution if you just need to refresh the entire page
refreshPage() {
window.location.reload();
}
Upvotes: 33
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
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
Reputation: 1642
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 shouldReuseRoute
because new TSLint rules won't allow non-arrow functions.
Upvotes: 77
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
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