42

Although this question seems to have popped up before, I can't find an answer that works for me, as the router seems to have changed a lot over the lifetime of angular.

In angular 5 I have a component where I wish to edit a user. I navigate to that component with the following code:

this.router.navigate(['editsingleuser',user.username])

Which will send me to /editsingleuser/bob

Then, from within that component I can also click on a button to edit my own user details, which uses the following code:

this.router.navigate(['editsingleuser',this.user.sub])

Which should send me to /editsingleuser/joe, but does not

Is there a parameter that I can add to the router.navigate that forces it to load the route, as it seems to be doing some kind of caching?

I have also tried using

[routerLink]="['editsingleuser',user?.sub]" 

which also has the same issue

Amirhossein Mehrvarzi
  • 18,024
  • 7
  • 45
  • 70
jazza1000
  • 4,099
  • 3
  • 44
  • 65

8 Answers8

42

I faced the same issue and this solved it in my case

constructor(private router: Router) {
    this.router.routeReuseStrategy.shouldReuseRoute = function () {
      return false;
    };
  }
Michael Meister
  • 711
  • 1
  • 7
  • 12
30

In Angular 8, it is possible to load some other route and then return to the current active one. Just try this:

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

Credits:

  1. How to reload the current route with the angular 2 router
  2. https://dev.to/oleksandr/mastering-angular-8-five-things-that-are-good-to-know-to-save-your-time-14hk (Item #5: #5. Reload component on same URL navigation)
Eduardo Vazquez
  • 2,454
  • 1
  • 12
  • 8
  • 1
    It doesn't work, it navigates to the first url shortly before navigating to the second url. – Boat Aug 07 '20 at 13:27
  • Yes, that's the purpose: To navigate to a different route before going to the actual route you want to go. In this case, as the question is asking, they wanted to go to the same route they already were but with different params: "angular navigate to the same route with different parameter" – Eduardo Vazquez Aug 09 '20 at 14:09
  • Can you write test cast for above code ? – Afsar Oct 12 '22 at 17:57
21

The answer to this problem was that I had to subscribe to the route parameter in my EditSingleUser component, and use this value when I fetched the data for the page

In ngOnInit()

this.route.params
  .switchMap((p: Params)=>{
      let usr = p['username']; //read the username route parameter
      return this.apiService.getUser(usr)}      //call getUser with that parameter
        )
  .subscribe(data=> {
    this.user= data
    console.log("data :" + JSON.stringify(data));
    this.setupFormData();          //use the resulting data to set up the form
  })
jazza1000
  • 4,099
  • 3
  • 44
  • 65
12

As of 5.1, Angular has a setting for route reloading. It's a parameter called

onSameUrlNavigation

https://angular.io/api/router/ExtraOptions

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

I suggest against using this technique though.

Angular's default behaviour does not reload the route when you navigate to the same route. It's a nice fail safe and it makes sense.

However, if you are changing the parameters, you could subscribe to the parameter change and act accordingly like this for example:

@Component({
  selector: 'app-custom-edit',
  templateUrl: './custom-edit.component.html',
  styleUrls: ['./custom-edit.component.scss']
})
export class CustomEditComponent implements OnInit {

  constructor(private route: ActivatedRoute) { }

  ngOnInit() {
    this.route.params.subscribe(res => {
      if (+res.id === 0) this.initNew() // 'id' here is an example url parameter
      else this.initExisting(+res.id)
    })
  }

  initNew() {
    //..
  }

  initExisting(id: number){
    //..
  }
}

And, by accordingly meaning, you could handle a set or reset of your component based on the parameter reality. Take it as your job, not the router's. This trigger will fire on the first initialization and when navigating to the same url with different parameters.

At the very least, it's more efficient than reloading the entire route.

ginalx
  • 1,905
  • 1
  • 15
  • 19
1

You can't navigate to editsingleuser/joe because you are already in editsingleuser route. If you will to navigate from editsingleuser to the same route, than you should change following code in your editsingleuser component:

this.router.navigate(['editsingleuser',this.user.sub]);

to this:

this.router.navigate(['/editsingleuser',this.user.sub]);

So you say to router, that you will go globaly to route editsingleuser.

Here I create an working example for you.

Gregor Doroschenko
  • 11,488
  • 5
  • 25
  • 37
  • This could use a bit more explanation. When trying to navigate to editsingleuser/joe while at editsingleuser/bob, does that get evaluated as trying to navigate to editsingleuser/bob/editsingleuser/bob ? – jcairney Oct 18 '18 at 15:14
1

What you want is not a strange job in Angular! I created a project in Stackblitz to show you how a component will be rendered (re-instantiated) again even if you are at the same component.

Note that you should define a route with parameter in app.routing.module for the corresponding component like below where I defined username parameter for catalog:

 RouterModule.forRoot([
      { path: 'login', component: LoginViewComponent },
      { path: 'home', component: HomeViewComponent },
      { path: 'catalog/:username', component: CatalogViewComponent },
      { path: '**', redirectTo: 'login' }
 ])

Then navigate to it like the following :

<a routerLink="/catalog/foo">Catalog 1</a> |

<a routerLink="/catalog/bar">Catalog 2</a> 

If the URL doesn't change, there's a problem with your variables which are used as parameter. There's no difference whether you employ this.router.navigate or [routerLink] in this case.

And then consume it at the catalog.component.ts.

Amirhossein Mehrvarzi
  • 18,024
  • 7
  • 45
  • 70
  • I don't really understand your answer. The url changes, but it does not RELOAD the component, without using the solution provided by Michael Meister. – VSO Dec 06 '19 at 15:33
  • What do you mean for RELOAD? There's no reload in SPA platforms by default. If you mean re-init ( `ngOnInit()` ), it has – Amirhossein Mehrvarzi Dec 07 '19 at 13:40
  • the component doesn't reset though. onInit is called but .ts component defined variable values are not reset. they're the old values from the previous version of the component! – fIwJlxSzApHEZIl Feb 02 '22 at 18:04
  • @fIwJlxSzApHEZIl You can easily see the value changes on the screen by navigating to different catalog pages! – Amirhossein Mehrvarzi Feb 02 '22 at 21:26
0

I would do something like this:

constructor(private router: Router, private route: ActivatedRoute) { }

/**
 * Navigate to User Details
 *
 * @summary Navigates to User Details Page
 * @param userId: string
 * @returns void
 */
 navigateToUserDetails(userId: string): void {
    this.router.navigate(['.', userId], { relativeTo: this.route.parent });
 }

This solution avoids hardcode URL fragments in the code. Preventing issues if the 'editsingleuser' URL fragment is changed for some reason.

So, I believe the trick here is the this.route.parent if your route child path is something like :userId

mmcorrelo
  • 946
  • 1
  • 10
  • 10
0

After a lot of search and time spent, I got a simple trick. That is to create a duplicate path for the same component on route like and use them interchangeably during navigation


// on the router
route = [

{'path1',component: Component1},
{'path2',component: Component1}

];

//on the component

this.url = (this.url=='path1')?'path2':'path1';

this.router.navigate([this.url],{id: this.id});