Your Blazor component needs data in a certain format, where to Map?
Blazor components can accept parameters of virtually any type.
This makes for a simple option when you fetch data from a backend API/service as you can often use that data “as is” in your component.
For example, you might call an API to fetch product details which returns a list of items of type Product. The chances are you can just use that directly in your Blazor UI.
@foreach(var product in products) { <ProductDetails Product="@product"/>}In this example the ProductDetails component is specific to this page, and tightly coupled to the structure of the incoming Product data, so this feels like a sound approach.
Another option is to have your component accept primitives like string, or int, and send those in to the component.
<ProductDetails name="@product.Name" price="@product.Price" />Now we could use ProductDetails anywhere we like, so long as we give it values for its Name and Price.
But, what if we have a truly re-usable component that needs to accept data in a certain format.
For example, let’s say we have a TreeView component which takes in a list of TreeItem objects.
TreeView.razor
[Parameter]public List<TreeItem> Items { get; set; }TreeItem.cs
public class TreeItem {
public string Name { get; set; }
public List<TreeItem> Children { get; set; }
}You can imagine this could be useful for showing nav items, or a folder tree, or anything else with a ‘Tree Like’ structure.
But now we’ve got a problem!
Every time we use this TreeView component, we need to map the data we’re trying to use (often from a backend API or service) to a list of TreeItem.
For example, we might pull a list of folders from a server and want to render those as a Tree.
FolderView.razor
<TreeView Items="?"/>@code {
protected override void OnInitialized() { var folders = _backendAPI.ListFolders(); // map folders to items of type `TreeItem` }
}So where do we put the mapping code?
Well, one option in this case is to write the mapping code directly in the component (FolderView in this case):
FolderView.razor
<TreeView Items="treeItems"/>@code {
List<TreeItem> treeItems = new();
protected override void OnInitialized() { var folders = _backendAPI.ListFolders();
foreach(var folder in folders){ treeItems.Add(new TreeItem { Name= folder.Name }); // possibly map sub folders here as well } }
}This is probably fine if the mapping code is simple/minimal (as above).
But if you’re mapping between objects with more properties, and perhaps a bit more logic to ensure the correct data comes out the other side, this can turn into a lot of messy code.
So where else could it go?
Enter Extension Methods - An Alternative#
This is where I quite often turn to extension methods.
You can create a separate method (in a separate class, in a separate file) which has the sole job of mapping data from your backend type to the structure needed for your component.
public static class FolderExtensionMethods{ public static IEnumerable<TreeItem> ToTreeItems(this List<Api.Folder> folders) { List<TreeItem> treeItems = new List<TreeItem>();
foreach (var folder in folders) { treeItems.Add(new TreeItem { Name = folder.Name }); // possibly map sub folders here as well }
return treeItems; }}Or, for bonus points, you can use yield return here for a more succinct version 🎯
public static class FolderExtensionMethods{ public static IEnumerable<TreeItem> ToTreeItems(this List<Api.Folder> folders) { foreach (var folder in folders) { // additional mapping goes here yield return new TreeItem { Name = folder.Name }; } }}Either way, you can use this extension method in your component, and your data is successfully mapped!
FolderView.razor
@using FolderExtensionMethods;<TreeView Items="treeItems"/>@code {
IEnumerable<TreeItem> treeItems;
protected override void OnInitialized() { var folders = _backendAPI.ListFolders(); treeItems = _folders.ToTreeItems(); }
}Your component remains easy to read, understand and maintain, plus you’ve encapsulated all that unsightly mapping code into a separate method which you can invoke at will.
Struggling to figure out what to focus on with Blazor?
BlazorSharp - The .NET Web Developers community is here to help!
- Connect with your fellow .NET web developers
- Keep up to date with the latest .NET changes
- Exchange tips, tools and tactics