DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Rediscovering Angular: Modern Advantages and Technical Stack
  • Angular Input/Output Signals: The New Component Communication
  • Azure Deployment Using FileZilla
  • Angular RxJS Unleashed: Supercharge Your App With Reactive Operators

Trending

  • AI Agents: A New Era for Integration Professionals
  • Securing the Future: Best Practices for Privacy and Data Governance in LLMOps
  • System Coexistence: Bridging Legacy and Modern Architecture
  • Simpler Data Transfer Objects With Java Records
  1. DZone
  2. Coding
  3. Frameworks
  4. Angular Router: Empty Paths, Componentless Routes, and Redirects

Angular Router: Empty Paths, Componentless Routes, and Redirects

We look through some code that shows us how to use some advanced pattern-matching with Angular's URL matching engine.

By 
Victor Savkin user avatar
Victor Savkin
·
Jul. 04, 16 · Tutorial
Likes (7)
Comment
Save
Tweet
Share
70.6K Views

Join the DZone community and get the full member experience.

Join For Free

At the core of the Angular router lies a powerful URL matching engine which transforms URLs and converts them into router states.

Image title

In this article, I will show how to use three of the engine’s features: empty-path routes, componentless routes, and redirects. And how using them together, we can implement advanced patterns in just a few lines of code.

Empty-Path Routes

Let’s start with this configuration.

[
  {
    path: 'team/:id',
    component: TeamComponent,
    children: [
      {
        path: 'users',
        component: AllUsersComponent
      },
      {
        path: 'user/:name',
        component: UserComponent
      }
    ]
  }
]


When navigating to ’/team/11/user/bob’, the router will instantiate the team component with the user component in it. And when navigating to ’/team/11/users’, the router will show the list of all users. This configuration works. But a more common way of doing this would be to render the list when navigating to /team/11. That’s what empty-path routes are for.

[
  {
    path: 'team/:id',
    component: TeamComponent,
    children: [
      {
        path: '',
        component: AllUsersComponent
      },
      {
        path: 'user/:name',
        component: UserComponent
      }
    ]
  }
]


By setting ‘path’ to an empty string, we can create a route that instantiates a component but does not “consume” any URL segments.

There is nothing really special about such a route. For instance, as any other route, it can have children.

[
  {
    path: 'team/:id',
    component: TeamComponent,
    children: [
      {
        path: '',
        component: WrapperComponent,
        children: [
          {
            path: 'user/:name',
            component: UserComponent
          }
        ]
      }
    ]
  }
]


In this example, when navigating to ’/team/11/user/jim’, the router will instantiate the wrapper component with UserComponent in it.

Matching Strategies and Redirects

To understand the second feature, let’s step back to think about how the router does matching. The router takes an array of routes and a URL, and tries to create a RouterState.

Let’s imagine we have this configuration, and we are navigating to ’/team/11/user/jim’.

[
  {
    path: 'team/:id',
    component: TeamComponent,
    children: [
      {
        path: 'user/:name',
        component: UserComponent
      }
    ]
  }
]


The router will go through the array of routes, which in this case there is only one, and it will check if the URL starts with the route’s path. Here it will check that ’/team/11/user/jim’ starts with 'team/:id’. Because it matches, the router will carry on matching by taking what is left in the URL and the matched route’s children. If the taken path through the configuration does not “consume” the whole url, the router backtracks to try an alternative path.

The default matching strategy is called 'prefix’ because a match is successful when a route’s path is the prefix of what is left in the URL. We can set the strategy explicitly, as follows:

[
  {
    path: 'team/:id',
    pathMatch: 'prefix',
    component: TeamComponent,
    children: [
      {
        path: 'user/:name',
        pathMatch: 'prefix',
        component: UserComponent
      }
    ]
  }
]


The router supports a second matching strategy–full, which checks that the path is “equal” to what is left in the URL. This is mostly important for redirects. To see why, let’s look at the this example:

[
  {
    path: '', //default pathMatch: 'prefix'
    redirectTo: 'teams'
  },
  {
    path: 'teams',
    component: TeamsComponent
  }
]


Most likely your intent is to render the Teams component when navigating to ’/teams’, and redirect to ’/teams’ when navigating to ’/’. But since the default matching strategy is 'prefix’, and an empty string is a prefix of any URL, the router will apply the redirect even when we are navigating to ’/teams’. Now, if we change the matching strategy to 'full’, the router will apply the redirect only when navigating to ’/’.

[
  {
    path: '',
    pathMatch: 'full',
    redirectTo: 'teams'
  },
  {
    path: 'teams',
    component: TeamsComponent
  }
]


Absolute Redirects

If the 'redirectTo’ value starts with a ’/’, then it is an absolute redirect. The next example shows the difference between relative and absolute redirects.

[
  {
    path: 'team/:id',
    component: TeamComponent,
    children: [
      {
        path: 'org/:name',
        redirectTo: '/org/:name'
      },
      {
        path: 'legacy/user/:name',
        redirectTo: 'user/:name'
      },
      {
        path: 'user/:name',
        component: UserComponent
      }
    ]
  },
  {
    path: 'org/:name',
    component: OrgComponent
  }
]


When navigating to ’/team/11/legacy/user/jim’, the router will apply the second redirect and will change the URL to ’/team/11/user/jim’. In other words, the part of the URL corresponding to the matched path will be replaced. But navigating to ’/team/11/org/eng’ will replace the whole URL with ’/org/eng’.

Componentless Routes

It is often useful to share parameters between sibling components. In this example, we have two components—TeamListComponent and TeamDetailsComponent—that we want to put next to each other, and both of them require the team id parameter. TeamListComponent uses the id to highlight the selected team, and TeamDetailsComponent uses it to show the information about the team.

One way to model that would be to create a bogus parent component, which both TeamListComponent and TeamDetailsComponent can get the id parameter from, i.e. we can model this solution with the following configuration:

[
  {
    path: 'team/:id',
    component: TeamParentComponent,
    children: [
      {
        path: '',
        component: TeamListComponent
      },
      {
        path: '',
        component: TeamDetailsComponent,
        outlet: 'details'
      }
    ]
  }
]


With this configuration in place, navigating to ’/team/11’ will result in this component tree:

AppComponent -> TeamParentComponent -> TeamListComponent
                                    -> TeamDetailsComponent


This solution has two problems. First, we need to create the team parent component, which serves no real purpose. Second, TeamListComponent and TeamDetailsComponent have to access the id parameter through the parent, which makes them less reusable. Because this use case is so common, the router supports a feature called componentless routes.

Componentless routes “consume” URL segments without instantiating components.

Let’s change the 'team/:id’ route to make it Componentless.

[
  {
    path: 'team/:id',
    children: [
      {
        path: '',
        component: TeamListComponent
      },
      {
        path: '',
        component: TeamDetailsComponent,
        outlet: 'aux'
      }
    ]
  }
]


Now, when navigating to ’/team/11’, the router will create the following component tree:

AppComponent -> TeamListComponent
             -> TeamDetailsComponent


Why is this better? First of all, we got rid of the bogus component. Second, since there is no component associated with the ’/team/:id’ route, the router will merge its params, data, and resolve into the children. As a result, TeamListComponent and TeamDetailsComponent can access the id parameter directly, without going through the parent route.

Composing Empty-Path Routes, Componentless Routes, and Redirects

What is really exciting about all these features is that they compose very nicely. And we can use them together to implement advanced patterns in just a few lines of code.

Let me give you an example. We’ve learned that we can use empty-path routes to instantiate components without consuming any URL segments, and we can use Componentless routes to consume URL segments without instantiating components. What about combining them?

[
  {
    path: '',
    canActivate: [CanActivateTeamsOrOrgs],
    resolve: {
      token: TokenNeededForBothTeamsAndOrgs
    },

    children: [
      {
        path: 'teams',
        component: TeamsComponent
      },
      {
        path: 'orgs',
        component: OrgsComponent
      }
    ]
  }
]


Here we’ve defined a route that neither consumes any URL segments nor creates any components, but is used merely for running guards and fetching data that will be used by both TeamsComponent and OrgsComponent.

Next example, although contrived, shows how we can use the three features to implement interesting URL transformations.

[
  {
    path: 'team/:id',
    children: [
      { path: '', pathMatch: 'full', redirectTo: 'list' },
      { path: 'list', component: TeamListComponent,
        children: [
       { path: '', pathMatch: 'full', redirectTo: 'default' },
       { path: 'default', component: DefaultComponent }
        ]
      },
      { path: '', pathMatch: 'full', redirectTo: 'details' outlet: 'aux' }
    ]
  }
]


With this configuration in place, the navigation to 'team/11’ will result in 'team/11/(list/default//aux:details).

Learn More

  • Follow Victor on twitter to learn more about the router
AngularJS

Published at DZone with permission of Victor Savkin, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Rediscovering Angular: Modern Advantages and Technical Stack
  • Angular Input/Output Signals: The New Component Communication
  • Azure Deployment Using FileZilla
  • Angular RxJS Unleashed: Supercharge Your App With Reactive Operators

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!