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?
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.
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
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.
init
function,
init
?
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.
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.
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';
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.
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 works for me like a charm
this.router.navigateByUrl('/', {skipLocationChange: true}).then(()=>
this.router.navigate([<route>]));
Little tricky: use same path with some dummy params. For example-
refresh(){
this.router.navigate(["/same/route/path?refresh=1"]);
}
this.router.navigate(['/pocetna'], { queryParams: { 'refresh': 1 } });
and route.queryParams.subscribe(val => myRefreshMethod())
where route: ActivatedRoute
is injected in refreshed component... Hope it helps
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]);
});
}
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) {
}
For me works hardcoding with
this.router.routeReuseStrategy.shouldReuseRoute = function() {
return false;
// or
return true;
};
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 :)
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.
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.
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.
A little bit hardcore but
this.router.onSameUrlNavigation = 'reload';
this.router.navigateByUrl(this.router.url).then(() => {
this.router.onSameUrlNavigation = 'ignore';
});
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 () {
}
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})
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()}])
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.
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)
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));
}
}
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();
}
In my case:
const navigationExtras: NavigationExtras = {
queryParams: { 'param': val }
};
this.router.navigate([], navigationExtras);
work correct
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"
.
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,
},
});
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'];
});
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;
}
})
}
This below code will work:
logoFn(url: any) {
this.router.routeReuseStrategy.shouldReuseRoute = function () {
return false;
};
this.router.navigate(['']); or
this.router.navigate([url]);
}
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
queryParamsMap
subject only gets updated the first time, but not on any subsequent updates.
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;
}
});
Success story sharing
'/'
instead of'/DummyComponent'