Blazor – 4 DynamicComponent Examples – ASP.NET Core 6

We have ASP.NET Core 6 previews!

So let’s explore one of the new features in ASP.NET Core 6 for Blazor: DynamicComponent.

As its name implies, DynamicComponent is a component that allows us to dynamically render components. The idea is that we pass the type of the component to render, and, optionally, its parameters, and voila, the component is rendered.

And what are we supposed to gain from this? Well, basically, save code in scenarios where we need to dynamically render components. To do this without DynamicComponent, we would always need to work with an if or a switch. We don’t have to use those with DynamicComponent.

To use DynamicComponent we do the following:

<DynamicComponent Type="type" />

Where type is the type of the component to render. Thus, if we pass it the SurveyPrompt type, then the SurveyPrompt component is rendered. In the same way, if we pass it ButtonComponent, then the ButtonComponent is rendered, etc.

We can also pass parameters to it using an IDictionary<string, object> to its Parameters property:

<DynamicComponent Type="type" Parameters="parameters" /> 

Let’s see a few concrete examples of how to use the new DynamicComponent.

Example 1 – Basic Use

We will start with a basic usage example. Suppose we want to render the SurveyPrompt component using DynamicComponent. For that we can say:

<DynamicComponent Type="type" />

@code {
	Type type = typeof(SurveyPrompt);
}

If we want, we can pass parameters to SurveyPrompt using a dictionary:

<DynamicComponent Type="type" Parameters="parameters" />

@code {
	Type type = typeof(SurveyPrompt);
	IDictionary<string, object> parameters = new Dictionary<string, object> 
     { { "title", "my title" } };
}

In this way, we pass the title parameter, with value “my title”, to the SurveyPrompt component. The result is as follows:

Example 2 – Using a Select to Change the Component

We are going to use a Select to dynamically change the component to render. First, let’s create the following two components:

CheckBoxComponent

<input type="checkbox" /> Label

TextboxComponent

<input type="text" @bind="text" /> @text
 
@code {
    string text = "";
}

Note that the TextboxComponent component also has functionality, this is to show that we can render components that have functionality, and not just components with UI to display. Now, we are going to use a Select to dynamically change the type sent to the DynamicComponent:

<div>
	<select @onchange="onChange">
		<option value="@nameof(CheckboxComponent)">@nameof(CheckboxComponent)</option>
		<option value="@nameof(TextboxComponent)">@nameof(TextboxComponent)</option>
	</select>
</div>
<DynamicComponent Type="type" />

@code {
	string namespaceComponents = "Blazor6.Client.Shared.";
	Type type = typeof(CheckboxComponent);

	private void onChange(ChangeEventArgs e)
	{
		type = Type.GetType($"{namespaceComponents}{e.Value.ToString()}");
	}
}

As you can see, what we do is use an @onchange to execute the onChange method, and from there change the value of the type variable. We use Type.GetType to get the type of the class. Notice that we have to pass the full namespace to it, that is: namespace.classname. In my case, I have placed the namespace in a variable called namespaceComponents.

The result of this is the following:

Example 3 – Communication from Child to Parent with DynamicComponent

When we want to send a message from a child component to a parent component, we usually use events with a parameter of the EventCallback type. That is not an option with DynamicComponent, since the Parameter is of type IDictionary<string, object>, so we cannot pass an event in the dictionary.

One solution is to use cascading parameters. We remember that with cascading parameters we can have parameters that we can use from any child component, without having to receive it through an attribute such as Parameter.

First, we need a class which will contain the type of data to send in the cascade parameter:

public class AppState
{
    public Action Action { get; set; }
    public Action<Dictionary<string, object>> ActionWithParameters { get; set; }
}

In our case we are using two properties: One that has an Action that does not receive parameters and one that does receive parameters. The one that receives parameters receives a Dictionary<string, object>. It is important to take into account that these parameters will be sent from the child component to the parent component. This is useful when we want to receive multiple values from the child component. We could also use a class for this instead of a dictionary if we wanted.

Now, suppose we have the following component, which receives a cascading parameter:

ButtonComponent

<button @onclick="handleClick">Click me</button>

@code {
	private void handleClick()
	{
		appState.Action?.Invoke();

		var dictionary= new Dictionary<string, object>() { 
		{ "key 1", "value 1" }, 
		{ "key 2", "value 2" } };
		
		appState.ActionWithParameters?.Invoke(dictionary);
	}

	[CascadingParameter] public AppState appState { get; set; }
}

As we can see, this component consists of a button, which, when clicked, executes the handleClick method. And, in handleClick what we do is use the Action and ActionWithParameters methods and invoke them. Notice that the second one we do it by passing the dictionary with the values that we want to send to the parent component.

Note: We are using both Action and ActionWithParameters, just because this is a tutorial, in real life you will probably only use one at a time.

Finally, let’s see the parent component in action:

<CascadingValue Value="appState">
	<DynamicComponent Type="typeof(ButtonComponent)" />
</CascadingValue>

@code {
	AppState appState = new AppState();
	protected override void OnInitialized()
	{
		appState.Action = HandleClick;
		appState.ActionWithParameters = HandleClickParameters;
	}

	private void HandleClick()
	{
		Console.WriteLine("Parent Component: Handle Click");
	}

	private void HandleClickParameters(Dictionary<string, object> dictionaryParams)
	{
		foreach (var param in dictionaryParams)
		{
			Console.WriteLine($"{param.Key}: {param.Value}");
		}
	}
}

As you can see, we have our DynamicComponent inside a CascadingValue, which we use to send an instance of appState.

Then, in the OnInitialized, we append the methods that we want to be executed when the user clicks on the button found in the ButtonComponent component.

Example 4 – Generating a Component from a JSON

The first time I heard about the DynamicComponent, immediately my mind thought of the scenario of rendering components from JSONs stored in a database.

So, I set out to do the same for this example, at least at the proof-of-concept level. The first thing we must do is create a JSON in the wwwroot (let’s imagine that the JSON comes from a database):

data.json

{
  "component": "SurveyPrompt",
  "parameters": {
    "title": "JSON title"
  }
}

As you can see, the previous structure says that we want to work with the SurveryPrompt component, and we want to use the title parameter, with the value “JSON title”.

Then, we create a class with this same structure:

public class JSONComponent
{
    public string Component { get; set; }
    public IDictionary<string, object> Parameters { get; set; }
}

Now, let’s look at the component that takes the JSON and uses it to generate render a component:

@page "/dynamic/example-4"
@inject HttpClient http
@using System.Text.Json

<h5>Example 4: Generating a Component from a JSON</h5>

@if (type != null)
{
	<DynamicComponent Type="type" Parameters="dictionary" />
}

@code {
	string namespaceComponents = "Blazor6.Client.Shared.";
	Type type;
	IDictionary<string, object> dictionary = new Dictionary<string, object>();
	
    protected async override Task OnInitializedAsync()
	{
		var json = await http.GetFromJsonAsync<JSONComponent>("/data.json");

		if (json.Parameters != null)
		{
			foreach (var parameter in json.Parameters)
			{
				var jsonElement = (JsonElement)parameter.Value;

				switch (parameter.Key)
				{
					case "title":
						dictionary.Add(parameter.Key, jsonElement.GetString());
						break;
					default:
						break;
				}

			}
		}

		type = Type.GetType($"{namespaceComponents}{json.Component}");
	}
}

As we can see, what we do is get the JSON using the HTTPClient. Then we check that it has parameters, and if it does, we add them to a dictionary.

It is important to note that we need to be careful with the data type of the value of the dictionary elements. Since if, for example, a parameter is of the integer type, we must use jsonElement.GetInt32() to be able to assign it to the dictionary, since if we pass a string, we will receive an error at runtime. That is why I was forced to use a switch to use the appropriate data type from the parameter’s name.

And there you have it! With the new DynamicComponent we can dynamically render components from type.

Courses

If you want to learn more about Blazor, or other technology like Angular and ASP.NET Core, buy one of my Udemy courses today:

  1. Building Applications with Angular 11 and ASP.NET Core 5: https://www.udemy.com/course/building-applications-with-angular-and-aspnet-core/?couponCode=JUNE2021
  2. Programming in Blazor – ASP.NET Core 5: https://www.udemy.com/course/programming-in-blazor-aspnet-core/?couponCode=JUNE2021
  3. Building RESTful Web APIs with ASP.NET Core 3.1: https://www.udemy.com/course/building-restful-web-apis-with-aspnet-core/?couponCode=JUNE2021
  4. Introduction to Concurrency in C# – Async and Paralellism: https://www.udemy.com/course/introduction-to-concurrency-in-c-async-and-paralellism/?couponCode=JUNE2021

Regards!

2 comments

  1. Using cascading parameters to solve for the lack of ability to pass in an Action in lieu of the EventCallback is pure genius and exactly what I needed to solve for! And there’s only about 3 articles published on the web at the moment about DynamicComponent, and you’re so far ahead of the others. Thanks so much for the time you’ve taken to think this through and create the blog post, Felipe. Saved me hours of head banging! 😀

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s