30

I have recently updated to the new RC3 and Router3alpha and it seems some things have changed.

I noticed that a click on the link of an active route does no longer result in the component to be reloaded. How do I achieve this behaviour with the new router3?

My link looks like

<a [routerLink]="['/link1']">Link1</a>

And to test I simply used a random number in ngOnInit:

export class LinkoneComponent implements OnInit 
{

    public foo: number;
    constructor() {}

    ngOnInit() 
    {
        this.foo = Math.floor(Math.random() * 100) + 1;
    }

}

It works just fine when switiching between routes, but a click on the currently active route does not result in a reload of the component.

Paolo Forgia
  • 5,804
  • 7
  • 39
  • 55
TommyF
  • 4,888
  • 5
  • 29
  • 49

11 Answers11

16

This is currently not supported. If only parameter values change but the route stays the same the component is not re-created.

See also https://github.com/angular/angular/issues/9811

You can subscribe to params to get notified when the params change to re-initialize the component instance.

See also https://stackoverflow.com/a/38560010/217408

Community
  • 1
  • 1
Günter Zöchbauer
  • 490,478
  • 163
  • 1,733
  • 1,404
  • yeah... I understand it. I will give you my bounty points ;) I do an ugly hack - redirect to dummy Url and then back to desired Url :) which cause component to be reused but it is a ugly hack. Did you plan to make it configurable? – Nikolay Rusev Jul 26 '16 at 12:41
  • 1
    I don't know if it is planned to be implemented. I think the next version should support a parameter for `router.navigate()` to skip history updates so you don't get these two redirects added to the history. – Günter Zöchbauer Jul 26 '16 at 12:45
  • yes. It will be good but this will not my original issue. It will be a step ahead of course :) thanks for your answers. – Nikolay Rusev Jul 26 '16 at 12:49
  • You could also try what I suggested in http://stackoverflow.com/questions/38971660/angular-2-reload-route-on-param-change – Günter Zöchbauer Aug 16 '16 at 10:01
7

As of Angular 5.1 this can now be done by using the onSameUrlNavigation configuration option as part of the built-in Angular router. It's fairly straightforward to set-up and get going although not obvious from the documentation.

The first thing you will need to do is set the option within your app.routing.ts if you have one or the file where your app routing is configured.

There are two possible values for onSameUrlNavigation 'reload' or false. The default value is false which causes nothing to happen when the router is asked to navigate to the active route. We want to set this value to reload. It is worth noting reload does not actually do the work of reloading the route, it only re-triggers events on the router that we then need to hook into.

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

To determine when those events are actually fired, you need to specify the runGuardsAndResolvers configuration option on your route. This can take three values...

paramsChange - only fire when route params have changed e.g. where the id in /user/:id changes

paramsOrQueryParamsChange - fire when a route param changes or a query param changes. e.g. the id or the limit property change in /user/:id/invites?limit=10

always - Always fire when the route is navigated

We want to specify always in this case. An example route is shown below.

export const routes: Routes = [
  {
    path: 'invites',
    component: InviteComponent,
    children: [
      {
        path: '',
        loadChildren: './pages/invites/invites.module#InvitesModule',
      },
    ],
    canActivate: [AuthenticationGuard],
    runGuardsAndResolvers: 'always',
  }
]

That is your router configured. The next step is to actually handle the events within one of your components. You will need to import the Router into your component and then hook into the events. In this example, I have hooked into the NavigationEnd event which is fired once the router has completed its navigation from one route to the next. Due to the way we have configured the app, this will now fire even if you try to navigate to the current route.

export class InviteComponent implements OnInit {
  constructor(
    // ... your declarations here
    private router: Router,
  ) {
    // subscribe to the router events
    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.
  }
}

The heavy lifting goes into the initialiseInvites() method, this is where you reset properties to their default values and fetch data from services to get the component back to its initial state.

You need to repeat this pattern across each component that you want to be able to reload when clicked or refresh through some form of refresh button, being sure to add the runGuardsAndResolvers option to each route in the routing file.

Simon McClive
  • 2,106
  • 3
  • 15
  • 13
  • 1
    I still don't think this is the solution most people ideally want when they say they want to reload or refresh the page. I think a great solution would just recreate the component, including destroying and rebuilding the components dom, which doesnt seem easy to do. Having to modify all your components with such a cross cutting concern isnt ideal. angular kinda sucks imo. – goat Mar 23 '18 at 06:48
  • 1
    I don't like this solution either. I am in a child route, navigating to another child route, both of which share the same data, which is resolved in the parent route. I have just submitted an update to the server, so I want to reload the whole route _programmatically_, so the parent resolver will fire again. I'm not navigating to the same URL, and I don't want to trigger a reload _every time_ I do... – Dan King Jul 25 '19 at 11:05
  • 1
    I was missing runGuardsAndResolvers: 'always' thanks – Ron Feb 11 '21 at 15:48
  • Exactly what I was looking for! – James Parker Mar 02 '21 at 18:58
7

Angular 2-4 current route reload hack

For me, using this method 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]);
    });
  }

You can attach this method to a click event on the current component to reload it.

indreed
  • 1,055
  • 11
  • 9
3

this worked for me, taken from this:

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

now you can use like: this.redirectTo(this.router.url);

suhailvs
  • 14,937
  • 8
  • 78
  • 88
2

This is the best hack that I've been able to come up to get around this annoying problem:

    var currentUrl = this.router.url;
    var refreshUrl = currentUrl.indexOf('someRoute') > -1 ? '/someOtherRoute' : '/someRoute';
    this.router.navigateByUrl(refreshUrl).then(() => this.router.navigateByUrl(currentUrl));

This works, but it's still a hack and I hate that the Angular team didn't provide a reload() method

Serj Sagan
  • 24,625
  • 17
  • 133
  • 166
  • 2
    Hackish and annoying, but it worked for me. Had to switch to `navigate([refreshUrl]);` for Angular 4, but otherwise perfect. It's stupid there's no reload method when this is such a common use case. For example, I needed to be able to quickly switch users and reload the current route for a customer demonstration. All of my components are ignorant of one another (as they should be) and the only shared service has no way to refresh the main component. – Will Nov 29 '17 at 19:51
  • 1
    Thanks for the solution. I was struggling to update a component related to a WorkflowService, because the application doesn't allow to refresh the actual component... You deserve a medal... – Joel Hernandez May 19 '20 at 16:29
1

For Angular 2 rc7 - router 3.0

Change base url in index.html to <script>document.write('<base href="/" />');</script>

supersonic
  • 187
  • 1
  • 4
0
if (currentUrl.indexOf('/settings') > -1) {
    this.router.navigateByUrl('/communication').then(() => this.router.navigateByUrl('/settings'));
} else {
    this.router.navigate(['/settings']);
}
Antti29
  • 2,815
  • 12
  • 34
  • 36
0

If you really need to trick the Router into reloading the component on each routerLink click, you can use the following code in your Component

constructor(private router: Router){
 // override the route reuse strategy
 this.router.routeReuseStrategy.shouldReuseRoute = function(){
    return false;
 }

 this.router.events.subscribe((evt) => {
    if (evt instanceof NavigationEnd) {
       // trick the Router into believing it's last link wasn't previously loaded
       this.router.navigated = false;
       // if you need to scroll back to top, here is the right place
       window.scrollTo(0, 0);
    }
});

}

Hope this helps

ǝsʞǝꓕ ɐuɹɐꓭ
  • 2,781
  • 7
  • 32
  • 43
0

I got into the same issue and I solved it using the LocationStrategy in my app module. Here it is how I implemented and will solve all the routing problems.

In app.module.ts

  • Add the HashLocationStrategy and LocationStrategy

    import { HashLocationStrategy, LocationStrategy } from '@angular/common';

  • Add in NgModule Provider

{
   provide: LocationStrategy,
   useClass: HashLocationStrategy
 }

Final app.module.ts Looks like this

import { NgModule }       from '@angular/core';
import { BrowserModule  } from '@angular/platform-browser';
import { AppComponent }   from './app.component';
import { HashLocationStrategy, LocationStrategy } from '@angular/common';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule],
    providers: [
                  {
                     provide: LocationStrategy, 
                     useClass: HashLocationStrategy
                  }
                ],
})

export class AppModule {}

For more information, you can follow these links HashLocationSt

NOTE: The above strategy will add # in your URL which I don't like. So I used alternative method:

ALTERNATIVE METHOD

Instead of using HashLocationStrategy, you can also use PathLocationStrategy.

Follow the following step which will remove the # and also work as expected in the above method

  • import the PathLocationStrategy from @angular/common
import { LocationStrategy, PathLocationStrategy } from '@angular/common';
  • Replace HashLocationStrategy to PathLocationStrategy in provider
  • Make sure your index.html is having base href as like below.

<base href="/">

Oliver
  • 443
  • 1
  • 6
  • 12
0

The JavaScript Window object exposes a location member that has a function called reload.

Use,

window.location.reload();

Refer: https://www.w3schools.com/jsref/met_loc_reload.asp

XPD
  • 1,024
  • 1
  • 12
  • 23
-4

In my modest opinion you could use the window.location.reload() in typescript. This way can be easy and secure because is a part of the browser functionalities.

Evan Wieland
  • 1,255
  • 1
  • 17
  • 29
Signeus
  • 11
  • 3
    And reload the whole angular app? Very bad idea – Ore Aug 08 '17 at 08:16
  • It's a bad idea only if you want to keep the application without lost the current information. But how do you reload or refresh the page? (The other way in my opinion is a service that to attach or deattach a template that do you want to refresh, but there are more effort in this task) – Signeus Aug 08 '17 at 17:09
  • 1
    Very bad idea indeed. Reloading an angular app is very very slow compared to just changing routes. – Arg0n Aug 17 '17 at 13:01
  • But it´s a good idea if you want to "clear" the current state – Mackelito Aug 25 '17 at 08:56