Manually changing the route parameters leads to inconsistent user interface

1.9k views Asked by At

Here is a plunker to play with:

https://plnkr.co/edit/qTjftING3Hk2fwN36bQa?p=preview

Everything works well, except when you manually change the id parameter in the url bar, because then the projects dropdown does not show the new projectId as current project. This happens when the user saves an url as favorite link and copy/paste it into the url bar! A common case I would say!

To fix this I can listen to route.params changes in the TestsListComponent and add a check with a sharedService/EventEmitter wheter the changed id exists in that dropdown. The bool return value existsProjectId inside the TestsListComponent decides wether I should redirect to the /projects page because the id did not exist.

But honestly, redirecting from the TestsListComponent is too late at least from a user experience perspective, because the route projects/:id/tests is already activated.

How would you fix that misbehavior?

P.S.

3

There are 3 answers

9
kemsky On BEST ANSWER

I'm not sure if i correctly understand your question, anyway here is my plunkr.

  this.router.events.subscribe(event => {

        if (event instanceof RoutesRecognized)
        {
          var first=event.state.root.firstChild.firstChild;
          var id = first && event.state.root.firstChild.firstChild.params['id'];
          console.debug('recognized', id);
          this.currentProject = this.projects[+id-1];

          console.log(this.currentProject);
        } 
  });

Just navigate to #/projects/1/tests.

10
Günter Zöchbauer On

There is no global params change one can subscribe to.

One approach is to locate the route and its params starting from the root router:

console.log('router', this.router.routerState.root.firstChild.firstChild && this.router.routerState.root.firstChild.firstChild.snapshot.params);

This can be done within this.router.events.subscribe((val) => { or within a router guard like canActivate or resolve https://angular.io/docs/ts/latest/guide/router.html#!#guards

1
Ibrahim El_Khatib On

Update your app.routes.ts file like below and use HashLocationStrategy, for reference: HashLocationStrategy

import {Routes, RouterModule} from '@angular/router';
import ProjectListComponent from './projects-list.component';
import TestsListComponent from './tests-list.component';
import OverviewComponent from './overview.component';
import {LocationStrategy, HashLocationStrategy} from '@angular/common';


export const routes: Routes = [
    { path: '', redirectTo: 'projects', pathMatch: 'full' },
    {
        path: 'projects', component: ProjectListComponent,
        children: [
            { path: ':id', redirectTo: ':id', pathMatch: 'full' },
            {
                path: ':id', component: OverviewComponent,
                children: [
                    { path: '', redirectTo: 'tests', pathMatch: 'full' },
                    { path: 'tests', component: TestsListComponent },

                ]
        ]
    }
];

export const appRoutingProviders: any[] = [
    {
        provide: LocationStrategy,
        useClass: HashLocationStrategy
    }
];

export const routing = RouterModule.forRoot(routes);