1

I have an issue with Angular routing I have two modules Basic and Dashboard

In the basic module, I can pass city param for not default city (for default city it should work without param, for example, if New York is default city the path will be http://my.domain/new-york and APP should use HomeComponent) but for not default application should use path http://my.domain/los-angeles and use the same component. List of cities I've got from the back-end. Next level of my structure is categories. I've got categories from the back-end too, but if I try to go to the http://my.domain/category I've got HomeComponent instead of SearchComponent. What the correct way to handle that?

I need:

http://my.domain/category -> SearchComponent
http://my.domain/city/category -> SearchComponent
http://my.domain/city -> HomeComponent
http://my.domain/ -> HomeComponent

app route config:

const routes: Routes = [
  {
    path: 'dashboard',
    canActivate: [AuthService],
    loadChildren: () => import('./modules/dashboard/dashboard.module').then(mod => mod.DashboardModule)
  },
  {
    path: '',
    loadChildren: () => import('./modules/basic/basic.module').then(mod => mod.BasicModule),
    runGuardsAndResolvers: 'always'
  },
  {
    path: '**',
    redirectTo: '/'
  }
];

Basic module routing

const routes: Routes = [
  {
    path: '',
    component: BasicComponent,
    children: [
      {
        path: '',
        component: HomeComponent,
        data: {
          headerDark: true
        }
      },
      {
        path: 'search',
        component: SearchComponent,
        pathMatch: 'full'
      },
      {
        path: ':city',
        component: HomeComponent,
        data: {
          headerDark: true
        },
      },
      {
        path: ':category',
        component: SearchComponent
      },
      {
        path: ':city/:category',
        component: SearchComponent
      },
      {
        path: ':city/search',
        component: SearchComponent,
        data: {
          headerDark: true
        }
      }
    ]
  }
];
2
  • i would suggest to have a city/:city route and a category/:category route. If you take a look to the url stackoverflow question, it's how it works : questions/:question Commented Aug 25, 2020 at 8:45
  • @GérômeGrignon thank you for your answer but that solution isn't good for me, also city/:city/:category gives me the same result( Commented Aug 25, 2020 at 8:53

2 Answers 2

3

I think you can solve it by implementing a custom UrlMatcher.

Here's the type definition for UrlMatcher:

export type UrlMatchResult = {
  consumed: UrlSegment[];
  posParams?: {[name: string]: UrlSegment};
};

export type UrlMatcher = (segments: UrlSegment[], group: UrlSegmentGroup, route: Route) =>
    UrlMatchResult|null;

Angular uses a defaultUrlMatcher for each of the route configuration objects. Its role is to determine the positional params(e.g :city) and the consumed segments(the segments that match the issued URL):

/* ... */
for (let index = 0; index < parts.length; index++) {
  const part = parts[index];
  const segment = segments[index];
  const isParameter = part.startsWith(':');
  if (isParameter) {
    posParams[part.substring(1)] = segment;
  } else if (part !== segment.path) {
    // The actual URL part does not match the config, no match
    return null;
  }
}

return {consumed: segments.slice(0, parts.length), posParams};

With this in mind, we could create a custom UrlMatcher that looks like this:

const cityMatcher: UrlMatcher = (segments, group, route) => {
  // you'll have to find the issued city name from `segments`
  // simply use console.log(segments) to find the proper way to do it
  // after you've found the name of the city, check if it is in the list of cities

  // if NOT in the list
  return null

  // if it is there
  return {
    consumed: segments.slice(0, 1),
    posParams: { city: nameOfTheFoundCity }
  }
}

And can be used like this:

{
  {
    path: ':city',
    component: HomeComponent,
    data: {
      headerDark: true
    },
    matcher: cityMatcher
  },
}

The same approach can be used for :category.

Sign up to request clarification or add additional context in comments.

Comments

0

I don't have the answer for you, but it probably has something to do with the path matching strategy.

Look here to see if adding pathMatch: 'Full' to one of your routes can solve your problem! I don't know which exact route you should add the pathMatch full strategy to but I believe the answer to your problem lies here.

Cheers

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.