I created this generic component to be able to pass a template for either list or grid view@*Usage Instructions:
The DynamicProductDisplay dynamically displays items in either a grid or list layout, depending on the user's selection. Pass a list of items to the `Items` parameter. Use the `GridViewTemplate` and `ListViewTemplate` parameters to specify how each item should be rendered in grid or list view respectively. To use DynamicProductDisplay with `GridProduct` and `ListedProduct`, define render fragments like this:<DynamicProductDisplay Items="products" GridViewTemplate="product => @<GridProduct Name="product.Name" ImageSource="product.ImageSource" Description="product.Description" Price="product.Price" OnAddToCart="() => AddToCart(product)" OnAddToFavorites="() => AddToFavorites(product)" />" ListViewTemplate="product => @<ListedProduct Name="product.Name" ImageSource="product.ImageSource" Description="product.Description" Price="product.Price" OnAddToCart="() => AddToCart(product)" OnAddToFavorites="() => AddToFavorites(product)" />" GridColumnClass="col-md-4" ListColumnClass="col-12" /> Replace `AddToCart` and `AddToFavorites` with your own event handlers. Parameters: - `Items`: The list of items to display. - `GridViewTemplate`: Render fragment defining how each item is rendered in grid view. - `ListViewTemplate`: Render fragment defining how each item is rendered in list view. - `GridColumnClass`: CSS class for grid layout columns. - `ListColumnClass`: CSS class for list layout columns.*@@typeparam TItem<div class="d-flex justify-content-end mb-3"><MudToggleIconButton @bind-Toggled="isGridView" Icon="@Icons.Material.Filled.GridView" ToggledIcon="@Icons.Material.Filled.ViewList" title="@buttonTitle" /></div><div class="row"> @if (Items != null) { @foreach (var item in Items!) {<div class="@gridOrListClass"> @if (isGridView) { @GridViewTemplate(item); } else { @ListViewTemplate(item); }</div> } }</div>@code { [Parameter] public List<TItem>? Items { get; set; } [Parameter] public bool isGridView { get; set; } = true; [Parameter] public RenderFragment<TItem>? GridViewTemplate { get; set; } [Parameter] public RenderFragment<TItem>? ListViewTemplate { get; set; } [Parameter] public string GridColumnClass { get; set; } = "col-md-4"; [Parameter] public string ListColumnClass { get; set; } = "col-12"; private string gridOrListClass => isGridView ? GridColumnClass : ListColumnClass; private string buttonTitle => isGridView ? "List View" : "Grid View";}my templates look like this:grid->
@typeparam TItem@inherits ComponentBase@* Summary of Usage: To use the GridProduct component, pass in the product's Name, ImageSource, Description, and Price as parameters. Optionally, set MaxDescriptionLength to control the displayed length of the Description. Provide EventCallback handlers for OnAddToCart and OnAddToFavorites to handle button clicks. Example usage:<GridProduct Name="product.Name" ImageSource="product.ImageSource" Description="product.Description" Price="product.Price" MaxDescriptionLength="50" OnAddToCart="() => AddToCart(product)" OnAddToFavorites="() => AddToFavorites(product)" />*@<MudCard Class="m-2 p-2" Elevation="2"><!-- Product image at the top --><MudCardMedia Image="@ImageSource" Alt="@Name" Class="product-image" Height="200" /><!-- Product name as title --><MudCardContent><MudText Typo="Typo.h6" Class="text-center">@Name</MudText><!-- Description with adjustable length --><MudText Typo="Typo.body2" Class="product-description text-center mt-1"> @DescriptionSubstring</MudText><!-- Product price --><MudText Typo="Typo.h6" Class="product-price text-center mt-1" Color="Color.Primary"> @Price.ToString("C")</MudText></MudCardContent><!-- Action buttons at the bottom of the card --><MudCardActions Class="d-flex justify-space-between"><MudButton Variant="Variant.Filled" Color="Color.Secondary" OnClick="@AddToCart"> Add to Cart</MudButton><MudButton Variant="Variant.Outlined" Color="Color.Tertiary" OnClick="@AddToFavorites"> Add to Favorites</MudButton></MudCardActions></MudCard>@code { [Parameter] public string Name { get; set; } = string.Empty; [Parameter] public string ImageSource { get; set; } = string.Empty; [Parameter] public string Description { get; set; } = string.Empty; [Parameter] public decimal Price { get; set; } [Parameter] public int MaxDescriptionLength { get; set; } = 100; [Parameter] public EventCallback OnAddToCart { get; set; } [Parameter] public EventCallback OnAddToFavorites { get; set; } private string DescriptionSubstring => Description.Length > MaxDescriptionLength ? $"{Description.Substring(0, MaxDescriptionLength)}..." : Description; private Task AddToCart() => OnAddToCart.InvokeAsync(null); private Task AddToFavorites() => OnAddToFavorites.InvokeAsync(null);}list->
@* Summary of Usage: To use the ListedProduct component, pass in the product's Name, ImageSource, Description, and Price as parameters. Optionally, set MaxDescriptionLength to control the displayed length of the Description. Provide EventCallback handlers for OnAddToCart and OnAddToFavorites to handle button clicks. Example usage:<ListedProduct Name="product.Name" ImageSource="product.ImageSource" Description="product.Description" Price="product.Price" MaxDescriptionLength="50" OnAddToCart="() => AddToCart(product)" OnAddToFavorites="() => AddToFavorites(product)" />*@@typeparam TItem@inherits ComponentBase<!-- The outer container using MudBlazor's MudPaper for styling and elevation --><MudPaper Class="p-2 m-2" Elevation="1"><MudGrid><!-- Left section of the grid to display the product image --><MudItem xs="12" sm="4"><MudImage Src="@ImageSource" Alt="@Name" Class="product-image" /></MudItem><!-- Right section of the grid for product details --><MudItem xs="12" sm="8"><MudText Typo="Typo.h6">@Name</MudText><!-- Displaying a limited description with customizable length --><MudText Typo="Typo.body2" Class="product-description"> @DescriptionSubstring</MudText><!-- Displaying the product price in bold and primary color --><MudText Typo="Typo.h6" Class="product-price" Color="Color.Primary"> @Price.ToString("C")</MudText><!-- Buttons for adding to cart and to favorites, invoking passed event callbacks --><MudButton Variant="Variant.Filled" Color="Color.Secondary" OnClick="@AddToCart">Add to Cart</MudButton><MudButton Variant="Variant.Outlined" Color="Color.Tertiary" OnClick="@AddToFavorites">Add to Favorites</MudButton></MudItem></MudGrid></MudPaper>@code { /// <summary> /// /// </summary> [Parameter] public string Name { get; set; } = string.Empty; [Parameter] public string ImageSource { get; set; } = string.Empty; [Parameter] public string Description { get; set; } = string.Empty; [Parameter] public decimal Price { get; set; } [Parameter] public int MaxDescriptionLength { get; set; } = 100; [Parameter] public EventCallback OnAddToCart { get; set; } [Parameter] public EventCallback OnAddToFavorites { get; set; } private string DescriptionSubstring => Description.Length > MaxDescriptionLength ? $"{Description.Substring(0, MaxDescriptionLength)}..." : Description; private Task AddToCart() => OnAddToCart.InvokeAsync(null); private Task AddToFavorites() => OnAddToFavorites.InvokeAsync(null);}I just can't get it to work.
Is my approach wrong or am I missing something?
I imagined doing something like this:
@page "/products-display"@aBunchOfUsings<DynamicProductDisplay TItem="ProductsDetailsListingModel" Items="SampleProducts.Products" GridViewTemplate="product => @<GridProduct Name='product.Name' ImageSource='product.ImageSource' Description='product.Description' Price='product.Price' OnAddToCart='() => AddToCart(product)' OnAddToFavorites='() => AddToFavorites(product)' />" ListViewTemplate="product => @<ListedProduct Name='product.Name' ImageSource='product.ImageSource' Description='product.Description' Price='product.Price' OnAddToCart='() => AddToCart(product)' OnAddToFavorites='() => AddToFavorites(product)' />"/>@code {}The whole point is that I want to keep the components generic and typeagnostic for reusage. Either I'm messing up the syntax when consuming the components or something else, I'm fairly new in programming so don't be afraid to correct anything at all.