Reputation: 3724
I am working on an Angular project. I'm struggling with refresh action in a component.
I would like to refresh the router's components on button click.
I have refresh button when I click on it the component/router need to be refresh.
I tried window.location.reload()
and location.reload()
these two are not suitable for my need. Please help if anyone aware of it.
Upvotes: 167
Views: 758159
Reputation: 2267
I notice not all asnwer are specific to the question as for components. Well then show them all, it depends a bit on your needs:
Generally, Method 2 or 3 are preferred as they provide a better user experience than a full page refresh.
import { Location } from '@angular/common';
constructor(private location: Location) {}
refresh() {
this.location.go(this.location.path());
window.location.reload();
}
import { Router } from '@angular/router';
constructor(private router: Router) {}
refresh() {
this.router.navigateByUrl('/', { skipLocationChange: true }).then(() => {
this.router.navigate([this.router.url]);
});
}
import { ChangeDetectorRef } from '@angular/core';
constructor(private cd: ChangeDetectorRef) {}
refresh() {
this.cd.detectChanges();
}
export class YourComponent {
refreshTrigger = 0;
refresh() {
this.refreshTrigger++;
this.ngOnInit();
}
}
And if something needs to be set some var or so and its not GUI related, you might do it in ngafterview. And in some rare cases you move things to constructor logic to be sure its available oince ngOninit fires.
Upvotes: 0
Reputation: 11
refreshPage() {
// save the current route in constant
const route = this.router.url;
// navigate to other route
this.router.navigate(['pages/dashboard'], { skipLocationChange: true
}).then(() => {
// return to the current route
this.router.navigate([route]);
});
}
Upvotes: 1
Reputation: 109
I know, this is an old question, but from my point of view, still a valid one. I came across the same issue, and none of the previous solutions were satisfying to me. The best solution, from my point of view, was this one:
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
this.router.onSameUrlNavigation = 'reload';
unfortunately, this is deprecated: https://angular.io/api/router/Router
After a while of research, I found a practical solution, which is suitable for all my needs and actually works with Angular 17.
Open your app.config.ts and extend your appConfig:
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes,
withRouterConfig({onSameUrlNavigation: 'reload'}),
),
{
provide: RouteReuseStrategy,
useClass: AppRouterReuseStrategy,
},
],
};
Create a new file, called: app.router-reuse-strategy.ts (or something else, doesn't matter) and paste the following content:
export class AppRouterReuseStrategy extends BaseRouteReuseStrategy {
override shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
window.scrollTo({top: 0, behavior: 'instant'})
return (future.routeConfig === curr.routeConfig) && !future.data['reloadComponent'];
}
}
Now you can enable the force reload the component, just by extending your routes
export const routes: Routes = [
{
path: '',
loadChildren: () => import('...').then(m => m.LandingRoutingModule),
},
{
path: 'persons',
loadChildren: () => import('...').then(m => m.PersonRoutingModule),
data: {
'reloadComponent': true
}
},
{
path: '**',
component: NotFoundComponent,
},
];
I hope this helps someone :-)
Upvotes: 5
Reputation: 837
Adding this to code to the required component's constructor worked for me.
this.router.routeReuseStrategy.shouldReuseRoute = function () {
return false;
};
this.mySubscription = this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
// Trick the Router into believing it's last link wasn't previously loaded
this.router.navigated = false;
}
});
Make sure to unsubscribe
from this mySubscription in ngOnDestroy()
.
ngOnDestroy() {
this.mySubscription?.unsubscribe();
}
Refer to this thread for more details - https://github.com/angular/angular/issues/13831
Upvotes: 31
Reputation: 3357
I came across this when looking for the same problem. And I found there were too many solutions across stackoverflow with similar/tweaked answers.
I believe the answer can be different based on what you're trying to achieve:
init()
function again)Summarizing the solutions here for easier reference:
Solution 1: Just call ngOnInit()
class MyComponent {
ngOnInit() {...}
reinitComponent() {
this.ngOnInit();
}
}
Notes:
Alternate syntax: Move this logic to a separate init()
function and call it in both places
class MyComponent {
ngOnInit() {
this.init();
}
init() { ... }
reinitComponent() {
this.init();
}
}
Solution 2A: Route to another route and return back to current route
import { ActivatedRoute, Router } from '@angular/router';
class MyComponent {
constructor(private route: ActivateRoute, private router: Router) {}
refreshPage() {
this.router.navigateByUrl('/', { skipLocationChange: true }).then(() => {
this.router.navigate([], { relativeTo: this.route });
});
}
Notes:
../..
to avoid recreating all components till the top)Solution 2B: Use Angular RouteReuseStrategy.shouldReuseRoute
This requires 3 steps:
Step 1: When configuring router module, use onSameUrlNavigation
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
@NgModule({
imports: [
RouterModule.forRoot(routes, {
onSameUrlNavigation: 'reload',
})
]
}
export class MyRoutingModule {}
Step 2: Change the RouteReuse strategy in Angular so that it does not reuse the component based on a queryParams
import { Injectable, NgModule } from '@angular/core';
import { ActivatedRouteSnapshot, BaseRouteReuseStrategy, RouteReuseStrategy, RouterModule } from '@angular/router';
@Injectable({ providedIn: 'root' })
class CustomRouteReuseStrategy extends BaseRouteReuseStrategy {
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return super.shouldReuseRoute(future, curr) && future.queryParams._refreshing !== 'true';
}
}
@NgModule({
providers: [
{
provide: RouteReuseStrategy,
useClass: CustomRouteReuseStrategy,
},
],
imports: [ // This is from Step 1
RouterModule.forRoot(routes, {
onSameUrlNavigation: 'reload',
})
]
}
export class MyRoutingModule {}
Step 3: And finally use it in a component
import { ActivatedRouteSnapshot, Router } from '@angular/router';
class MyComponent {
constructor(private router: Router, private route: ActivatedRoute) {}
refreshPage() {
router.navigate([], {
relativeTo: route,
queryParamsHandling: 'merge',
queryParams: { _refreshing: true },
skipLocationChange: true,
});
}
Notes:
Solution 3: Use angular configs to always run router events on same url
When configuring router module, use onSameUrlNavigation
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
@NgModule({
imports: [
RouterModule.forRoot(routes, {
onSameUrlNavigation: 'reload',
})
]
}
export class MyRoutingModule {}
Notes:
Solution 4: Tell the browser to refresh the page using Browser APIs
class MyComponent {
refreshBrowserTab() {
window.location.reload();
}
Notes:
Alternate syntax: Uses Angular's location which can be altered with DI to mock it during tests
import { Location } from '@angular/common';
class MyComponent {
constructor(private location: Location) {}
refreshBrowserTab() {
this.location.reload();
}
Upvotes: 3
Reputation: 605
Import ActivatedRoute and Router:
import { ActivatedRoute, Router } from '@angular/router';
Then add them to your constructor:
constructor(
private route: ActivatedRoute,
private router: Router,
)
After that in the function that you want the reloading of the page to happen:
reloadURL(): void {
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
this.router.onSameUrlNavigation = 'reload';
this.router.navigate(['./'], {
relativeTo: this.route,
});
}
It will then reload the very component that you are on, simple as that.
Upvotes: 0
Reputation: 770
private saveRouterStrategyReuseLogic: any;
ngOnInit() {
// Save logic
this.saveRouterStrategyReuseLogic = this.router.routeReuseStrategy.shouldReuseRoute;
this.router.routeReuseStrategy.shouldReuseRoute = (future, curr) => { return false; };
}
ngOnDestroy() {
this.router.routeReuseStrategy.shouldReuseRoute =
this.saveRouterStrategyReuseLogic;
}
Upvotes: 0
Reputation: 1960
calling ngOnInit()
does not work for my complicated component, I end up using this
reloadCurrentRoute() {
let currentUrl = this.router.url;
this.router.navigateByUrl('/', {skipLocationChange: true}).then(() => {
this.router.navigate([currentUrl]);
});
}
Upvotes: 21
Reputation: 480
Just change the routeReuseStrategy
from the angular Router:
this._router.routeReuseStrategy.shouldReuseRoute = function () {
return false;
};
Set the routerproperty "navigated" to false:
this._router.navigated = false;
Then navigate to your component:
this._router.navigate(['routeToYourComponent'])
After that reinstate the old/default routeReuseStrategy:
this._router.routeReuseStrategy.shouldReuseRoute = function (future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
You can also make a service out of this:
@Injectable({
providedIn: 'root'
})
export class RouterService {
constructor(
private _activatedRoute: ActivatedRoute,
private _router: Router
) { }
reuseRoutes(reuse: boolean) {
if (!reuse) {
this._router.routeReuseStrategy.shouldReuseRoute = function () {
return false;
};
}
if (reuse) {
this._router.routeReuseStrategy.shouldReuseRoute = function (future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
};
}
}
async refreshPage(url?: string) {
this._router.routeReuseStrategy.shouldReuseRoute = function () {
return false;
};
this._router.navigated = false;
url ? await this._router.navigate([url]) : await this._router.navigate([], { relativeTo: this._activatedRoute });
this._router.routeReuseStrategy.shouldReuseRoute = function (future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
};
}
}
Upvotes: 2
Reputation: 819
There are problems with some of the answers before:
This worked for me (I don't know if it is recommendable or optimal)
@Input()
tags: string[] = [];
constructor(public changeDetector: ChangeDetectorRef )
constructor(private vcrf: ViewContainerRef, private cfr: ComponentFactoryResolver, private elementRef: ElementRef) {
}
public loadComponent(): void {
const componentFactory = this.cfr.resolveComponentFactory(TagsListComponent);
const component = this.container.createComponent(componentFactory);
component.instance.tags = /* whatever data we want to pass */;
component.instance.changeDetector.markForCheck();
...
loadComponent() is a custom function that could be called, for example, once the parent page scrolls to some position in the parent component, indicating that the dynamic component should be shown.
Upvotes: 3
Reputation: 76
In my case I needed to reload specific routes (not all in the application), so adding the global setting {onSameUrlNavigation: 'reload'}
had no effect, while this.router.routeReuseStrategy.shouldReuseRoute = () => false
in the component works but modifies the global settings of the router.
The solution was to save the original router configuration to a variable before changing it in the component's constructor as indicated @abhishek-singh by the first answer of the problem.
private routeReuseStrategy:any;
constructor(
private router:Router
) {
this.routeReuseStrategy = this.router.routeReuseStrategy.shouldReuseRoute;
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
}
And when exiting the path, remap the original configuration using the OnDestroy hook.
public ngOnDestroy():void
{
this.router.routeReuseStrategy.shouldReuseRoute = this.routeReuseStrategy;
}
Upvotes: 0
Reputation: 1517
Just follow the below steps:
{onSameUrlNavigation: 'reload'}
as below in your app-routing.modules.ts@NgModule({
imports: [ RouterModule.forRoot(routes,{onSameUrlNavigation: 'reload'})],
exports: [ RouterModule ]
})
this.router.routeReuseStrategy.shouldReuseRoute = () => false
as below in you component ts file constructor:constructor(private router: Router) { this.router.routeReuseStrategy.shouldReuseRoute = () => false; }
this.router.navigate([/sameRoute]);
in the last.
replace sameRoute with your route url.For more details: https://medium.com/engineering-on-the-incline/reloading-current-route-on-click-angular-5-1a1bfc740ab2
I am using Angular 12.
Upvotes: 10
Reputation: 329
router.navigate['/path']
will only takes you to the specified path
use router.navigateByUrl('/path')
it reloads the whole page
Upvotes: 0
Reputation: 31
html file
<a (click)= "getcoursedetails(obj.Id)" routerLinkActive="active" class="btn btn-danger">Read more...</a>
ts file
getcoursedetails(id)
{
this._route.navigateByUrl('/RefreshComponent', { skipLocationChange: true }).then(() => {
this._route.navigate(["course",id]);
});
Upvotes: 0
Reputation: 159
this is little bit out of box and I dont know whether this helps you or not but have yo tried
this.ngOnInit();
its a function so whatever code you have in it will be recalled just like a refresh.
Upvotes: 13
Reputation: 115
just do this : (for angular 9)
import { Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';
constructor(@Inject(DOCUMENT) private document: Document){ }
someMethode(){ this.document.location.reload(); }
Upvotes: 0
Reputation: 4595
One more way without explicit route:
async reload(url: string): Promise<boolean> {
await this.router.navigateByUrl('.', { skipLocationChange: true });
return this.router.navigateByUrl(url);
}
Upvotes: 13
Reputation: 3724
After some research and modifying my code as below, the script worked for me. I just added the condition:
this.router.navigateByUrl('/RefreshComponent', { skipLocationChange: true }).then(() => {
this.router.navigate(['Your actualComponent']);
});
Upvotes: 183
Reputation: 11
constructor(private router:Router, private route:ActivatedRoute ) {
}
onReload(){
this.router.navigate(['/servers'],{relativeTo:this.route})
}
Upvotes: 1
Reputation: 11
kdo
// reload page hack methode
push(uri: string) {
this.location.replaceState(uri) // force replace and no show change
await this.router.navigate([uri, { "refresh": (new Date).getTime() }]);
this.location.replaceState(uri) // replace
}
Upvotes: 1
Reputation: 587
Fortunately, if you are using Angular 5.1+, you do not need to implement a hack anymore as native support has been added. You just need to set onSameUrlNavigation to 'reload' in the RouterModule options :
@ngModule({
imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: ‘reload’})],
exports: [RouterModule],
})
More information can be found here: https://medium.com/engineering-on-the-incline/reloading-current-route-on-click-angular-5-1a1bfc740ab2
Upvotes: 27
Reputation: 508
In my application i have component and all data is coming from API which i am calling in Component's constructor. There is button by which i am updating my page data. on button click i have save data in back end and refresh data. So to reload/refresh the component - as per my requirement - is only to refresh the data. if this is also your requirement then use the same code written in constructor of component.
Upvotes: 2
Reputation: 1779
Use the this.ngOnInit(); to reload the same component instead reloading the entire page!!
DeleteEmployee(id:number)
{
this.employeeService.deleteEmployee(id)
.subscribe(
(data) =>{
console.log(data);
this.ngOnInit();
}),
err => {
console.log("Error");
}
}
Upvotes: 116
Reputation: 1243
Other way to refresh (hard way) a page in angular 2 like this
it's look like f5
import { Location } from '@angular/common';
constructor(private location: Location) {}
pageRefresh() {
location.reload();
}
Upvotes: -4
Reputation: 222722
This can be achieved via a hack, Navigate to some sample component and then navigate to the component that you want to reload.
this.router.navigateByUrl('/SampleComponent', { skipLocationChange: true });
this.router.navigate(["yourLandingComponent"]);
Upvotes: 5