52

I've upgraded to use the new Angular 2 router from router-deprecated and some behavior has changed.

The page I'm having issues with is a search page. We've chosen to put all the search terms in the URL using the HashLocationStrategy. The routes look like this:

const routes: RouterConfig = [
  { path: '', component: HomeComponent },
  { path: 'search/:term/:cat/:page/:sort/:size/:more', component: HomeComponent },
  { path: 'search/:term/:cat/:page/:sort/:size', component: HomeComponent },
  { path: 'search/:term/:cat/:page/:sort', component: HomeComponent },
  { path: 'search/:term/:cat/:page', component: HomeComponent },
  { path: 'search/:term/:cat', component: HomeComponent },
  { path: 'search/:term', component: HomeComponent },
  { path: 'details/:accountNumber', component: DetailsComponent }
];

I know a query string approach might be better fit for all these options but project requirements decided by other people...

Anyway if I navigate to localhost/#/search/Hello using this.router.navigate(['/search/Hello']); then the router works fine and everything is great. While on that page if I try to this.router.navigate(['/search/World']); then the URL in the browser's address bar will update accordingly but the component doesn't change at all.

Previously I could use routerCanReuse to indicate that I did want to reuse the search component and routerOnReuse would rerun the search when the navigation happened. I don't see equivalent's to these in @angular/router. How can I reload the current route with new URL parameters?

I'm running version 2.0.0-rc.3 for Angular 2 and 3.0.0-alpha.8 of @angular/router.

Zze
  • 18,229
  • 13
  • 85
  • 118
Corey Ogburn
  • 24,072
  • 31
  • 113
  • 188
  • I am facing same problem.can you tell me where i can put this code on app.component.ts page or actual page(which is not getting reloaded). One more thing what is ** this.service.get(term).then(result => { console.log(result); });**. Can you explain in brief. – pushp Jun 09 '17 at 13:22

4 Answers4

70

If only the params has changes the component itself won't be initialize again. But you can subscribe to changes in the parameters that you send.

For example on ngOnInit method you can do something like this:

ngOnInit() {
    this.sub = this.route.params.subscribe(params => {
       const term = params['term'];
       this.service.get(term).then(result => { console.log(result); });
     });
  }
Doron Brikman
  • 2,444
  • 1
  • 16
  • 17
  • 4
    I was really curious why the params were an Observable. This explains it and makes a lot of sense. – Corey Ogburn Jun 30 '16 at 17:49
  • 12
    I don't understand this. The problem- or at least my problem- is that the ngOnInit function doesn't run again when the same route is called with a different parameter value. So what help is this...? – Inigo Nov 03 '16 at 02:00
  • 2
    The idea is that angular don't need to mount the component again. Only the data has change, specifically the route data. So what you have is a function that will invoke anytime the route data changed and you can react to this change. – Doron Brikman Nov 03 '16 at 09:34
  • i got the point..subscribing to param value change..but there needs to be some other configuration needed too..i am subscribing to param change..but still the component is getting reloaded.. – Lakshay Dulani Mar 03 '17 at 12:35
  • @Lakshay google for custom route reuse strategy or check [this answer](https://stackoverflow.com/questions/44875644/custom-routereusestrategy-for-angulars-child-module) – Daniel Kucal Jul 20 '17 at 00:47
  • @DoronBrikman I have a route which has a list of item now upon click I navigate to some other route of the same component sending a parameter now I need to query the data from the existing list instead of making a service call again how can I do that ? – Zaker Aug 24 '17 at 04:19
  • AFAICT, there is no doc on this critical behavior - some examples of straightforward use cases (e.g. just "get" the current parameter) would be helpful. The routing guide is cumbersome – Coruscate5 Oct 25 '17 at 20:32
  • wow! thanks @DoronBrikman, you save my day! I had a problem with a component that needed to be updated where the only change was in parameters, which in turn will dynamically cause update content. I was thinking there was a problem with browser history as component didn't update on url change, for example, when using location.back() to return to previous page. thanks again. – danfer Nov 23 '18 at 16:53
  • Three days trying to get a good help... I found this!!! TY! – Carlos Galeano Aug 24 '20 at 19:43
  • Thanks, great and simple solution, and now I understand why params are observables :) – Marcin Żmigrodzki Sep 20 '22 at 07:58
0

Probably, you don't need to run ngOnInit at all. And this is advantage of the angular router. What you can do is mentioned in the previous answer - subscribe to params or paramsMap (route.paramsMap: Observable<ParamMap> with Map interface).

There is another option - You can put your data retrieving to guard and re-run resolvers and guards on params change. Put runGuardsAndResolvers: 'paramsOrQueryParamsChange' in route configuration. Now it will be:

const routes: RouterConfig = [
{ 
     path: "search/:term/:cat/:page/:sort/:size/:more", 
     component: HomeComponent, 
     runGuardsAndResolvers: 'paramsOrQueryParamsChange' 
}, 
...];

Here you can find how to request data from api in resolvers.

Mariia Bilyk
  • 181
  • 1
  • 3
  • Hey @Marria, route.paramsMap will only emit value on change in param. In my case, if I navigate to /path;param=1 again. Want this route.paramsMap to emit value again. I have also tried `replaceUrl` flag but it won't trigger on same route with same param ` this.router.navigate(['path', params], { replaceUrl: true });` – Saurabh Gangamwar Nov 03 '21 at 19:03
0

For later versions of Angular, using ActivatedRoute to subscribe to param changes provides a simple mechanism for refreshing data.

Quoted from answer by @Evgeny Nozdrev: https://stackoverflow.com/a/68503542/1956540

For URL params (like /persons/:id):

import { ActivatedRoute } from '@angular/router';

constructor(protected activeRoute: ActivatedRoute, ...) {
    this.activeRoute.paramMap.subscribe(paramMap => {
        const id = paramMap.get('id');    // get param from dictonary
        this.load(id);                    // load your data
    });
}
BatteryAcid
  • 8,381
  • 5
  • 28
  • 40
-1

I faced the same problem and resolved this by making the router not to reuse the route. This can be done by writing this code in the constructor:

constructor(
    private router: Router,
) { 
    this.router.routeReuseStrategy.shouldReuseRoute = function () {
        return false;
    };
}
  • Be careful. This will affect the Router component globally, and your internal router links will stop working. – Alvaro VS Aug 30 '21 at 22:48