Telerik blogs

Learn how to implement child routes and use optional route parameters in Blazor for more advanced routing needs.

In this article, we explore child routes and optional route parameters in Blazor.

In a previous article of this Blazor Basics series, we learned the Blazor Routing and Navigation Fundamentals. That post would be a good place to start if you haven’t read it yet before we get into the more advanced routing options in this article.

Introduction

Routing and navigation are fundamental problems solved by modern single-page web application frameworks.

Static routes and simple parameter passing are often trivial and can be expressed with a few lines of code. However, it becomes interesting, more complex and often more code-intensive to solve advanced concepts, such as defining and using child routes and optional route parameters.

In this article, you will learn how we can implement advanced routing concepts using Blazor.

Child Routes

A child route is a route within another route. Sometimes, it’s also referred to as a nested route.

Blazor doesn’t have child routes, as you might know them from React or Angular, where router implementations offer a tree-like structure. However, we do not need real child routes in most use cases. Instead, we can use the regular Blazor way of defining routes using the @page directive.

The following code in an Order component shows a child route definition:

@page "/orders/{OrderId:int}/product/{ProductId:int}"

We have a parent route orders that accepts an int parameter OrderId. The child route for the product has a ProductId of type int as its parameter.

Instead of nesting the route definitions, we need to extend the route definition for every level we want to nest deeper.

Now take a look at the following Order component of a real-world scenario representing a single order in an ecommerce system:

@page "/orders/{OrderId:int}"

<h3>Order</h3>
<p>OrderId: @OrderId</p>

<h4>Products</h4>
<ul>
    <li><a href="/orders/@OrderId/product/42">Product 42</a></li>
</ul>

@code {
    [Parameter]
    public int OrderId { get; set; }
}

We provide the OrderId as the route parameter. We imagine there is an Orders page, which contains all orders, and this Order component displays a single order.

We also see a list of products that are listed in the order. We build a link to another page using a child route by extending the route defined at the top of this Order page component.

Now let’s see how the ProductOrder component is implemented:

@page "/orders/{OrderId:int}/product/{ProductId:int}"

<h3>Product Details</h3>

<p>OrderId: @OrderId</p>
<p>ProductId: @ProductId</p>

<p>Go to <a href="/orders/@OrderId">Order @OrderId</a></p>

@code {
    [Parameter]
    public int OrderId { get; set; }

    [Parameter]
    public int ProductId { get; set; }
}

We have the route definition, which has the ProductId at the end, matching the URL we constructed on the previous page to navigate to this page.

In the code section, we need to implement two properties. Each property holds the information of one of the route parameters.

At first, this might look like reinventing the wheel and typing the same code over and over again for each child’s route. While that is true, it is still an elegant and simple solution to express what we need in most situations.

It could be that we get real child routes in Blazor in the future. However, there has been a discussion going on for years, and the design and implementation of that feature have been postponed multiple times.

Suppose you are a React or Angular developer transitioning into Blazor and want to use true nested routes as they are available in those frameworks. In that case, there is an open-source third-party Blazor Router implementation by a community member.

The main reason for the delay is that the current router is simple and flexible, and it solves 99% of developers’ needs.

Type Constraints for Route Definitions

The following type constraints are available in Blazor for route definitions:

  • bool {isActive:bool}
  • int {age:int}
  • datetime {startdate:datetime}
  • decimal {price:decimal}
  • double {longitude:double}
  • float {value:float}
  • long {largeValue:long}
  • guid {myId:guid}
  • string {title}

I highly recommend using type constraints for all route definitions. If we do not specify a type constraint, Blazor treats the parameter as a string.

Optional Route Parameters

Now that we understand Routing in Blazor and have learned how to implement child routes, we are ready to explore optional route parameters.

Similar to child routes, Blazor doesn’t explicitly offer a feature to implement optional route parameters. However, once again, we can reuse an existing mechanism to do so.

Consider the following OptionalParameters component.

@page "/optional"
@page "/optional/{id:int}"
@page "/optional/{title}"

We define three different routes using the @page directive. Yes, we can use the @page directive multiple times on the same page. We register the page for different routes.

We access the values from the parameters as we access them when defining any parameterized route using properties in the code section.

@code {
    [Parameter]
    public int Id {get;set;}

    [Parameter]
    public string Title {get;set;}
}

The template code looks like this:

 class="prism  language-html"><p>Id: @Id<br />
Title: "@Title"</p>

<ul>
    <li><a href="/optional">Optional</a></li>
    <li><a href="/optional/11">Optional/11</a></li>
    <li><a href="/optional/my-title">Optional/my-title</a></li>
</ul>

For demonstration purposes, we implement the page with an Id and a Title property, both of which are rendered on the screen.

We use three links to reach the different routes.

Optional route parameters allow you to implement dynamic scenarios where you want to be able to navigate to a page from different angles with different parameters.

Besides having one or multiple optional route parameters, we can also define the data type for each parameter using type constraints.

Optional Route Parameters with Default Values

When working with optional route parameters, the property contains the default C# value of the type. In the case of a string, the property will contain an empty string if no value is provided. In the case of an int, the value will be 0.

However, we can specify the default value of optional route parameters in the component’s code.

First of all, we need to define the property as a nullable type. In this example, we change the definition of the Id property to a nullable int.

[Parameter]
public int? Id {get;set;}

Next, we override the OnInitialized lifecycle method and set the default value if the variable is null.

protected override void OnInitialized()
{
    Id = Id ?? 16;
}

This implementation ensures that the Id property contains either a value provided by the route parameter or the default value set in the statement within the OnInitialized method.

Conclusion

Blazor doesn’t provide a specific syntax to define child routes. However, we can reuse the @page directive to define a nested route.

Optional route parameters allow us to register a page with optional arguments and for multiple different parameter types.

Blazor supports nine different type constraints for route parameters. Blazor will treat the parameter as a string if we don’t specify the type.

We can specify default values when using optional route parameters by overriding the OnInitialized lifecycle method. In this case, we need to make sure that we use nullable properties.

You can access the code used in this example on GitHub.

If you want to learn more about Blazor development, you can watch my free Blazor Crash Course on YouTube. And stay tuned to the Telerik blog for more Blazor Basics.


About the Author

Claudio Bernasconi

Claudio Bernasconi is a passionate software engineer and content creator writing articles and running a .NET developer YouTube channel. He has more than 10 years of experience as a .NET developer and loves sharing his knowledge about Blazor and other .NET topics with the community.

Related Posts

Comments

Comments are disabled in preview mode.