jazza1000
jazza1000

Reputation: 4247

angular navigate to the same route with different parameter

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

Upvotes: 43

Views: 47730

Answers (8)

Sefefe Aragie
Sefefe Aragie

Reputation: 1

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}); 


Upvotes: 0

mmcorrelo
mmcorrelo

Reputation: 1004

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

Upvotes: 0

Eduardo Vazquez
Eduardo Vazquez

Reputation: 2574

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)

Upvotes: 34

ginalx
ginalx

Reputation: 2247

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.

Upvotes: 12

Amirhossein Mehrvarzi
Amirhossein Mehrvarzi

Reputation: 18944

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.

Upvotes: 1

Michael Meister
Michael Meister

Reputation: 737

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

constructor(private router: Router) {
    this.router.routeReuseStrategy.shouldReuseRoute = function () {
      return false;
    };
  }

Upvotes: 43

jazza1000
jazza1000

Reputation: 4247

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
  })

Upvotes: 22

Gregor Doroschenko
Gregor Doroschenko

Reputation: 11696

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.

Upvotes: 1

Related Questions