Products Module
With the products module, an author can manage product information in a structured and centralized way.
Display Product Information in a Page Component
In the following example, you will see how you can create a page component which will display some product attributes in a table, configured by the author.
First of all, create a page component model, which allows the author to select a product and product attributes to display.
public class ProductAttributeListViewModel
{
public ProductModel? Product { get; set; }
public IEnumerable<Guid> AttributeIds { get; set; } = [];
}
Then register the page component and build the form for the author.
module.Configure.RegisterConfinityContent<MyProductTableComponentModel>("My Product Table")
.Icon(Icon.Table)
.Editor(form =>
{
form.AddTab(tab =>
{
tab.AddSelectProduct(p => p.Product!)
.Validate(v => v.NotNull());
tab.AddSelectProductAttributes(p => p.Attributes!)
.Validate(v => v.NotNull());
});
});
Now create a ViewComponent which loads the product from the product service and prepare the data for the view.
public class MyProductTableComponent : ViewComponent
{
private readonly IProductService _productService;
public MyProductTableComponent(IProductService productService)
{
_productService = productService;
}
public async Task<IViewComponentResult> InvokeAsync(MyProductTableComponentModel model)
{
var viewModel = new ProductAttributeListViewModel()
{
Product = await _productService.GetProductAsync(model.Product?.Id),
AttributeIds = model.Attributes?.Select(p => p.Id) ?? []
};
return View("./MyProductTableComponent.cshtml", viewModel);
}
}
And finally we create the view for the component which will get all attributes from the product grouped by its attribute groups. Then we loop all attributes and display the values accordingly. In the following example you will find all kind of value types a product attribute can have.
@using Confinity.Assets
@using Confinity.Entities
@using Confinity.Models
@using Confinity.WebUI.Util
@using Microsoft.AspNetCore.Html
@model DocsDemos.Modules.Products.ProductAttributeListViewModel
@inject IAssetService AssetService;
@if (Model.Product != null)
{
foreach (var group in Model.Product
.GetGroupedAttributes()
.Where(p => p.Attributes.Any(p => p.Value != null && Model.AttributeIds.Contains(p.Id)
))
)
{
<h2>@group.Name</h2>
<table class="table table-bordered">
@foreach (var attr in group.Attributes
.Where(p => p.Value != null && Model.AttributeIds.Contains(p.Id))
)
{
<tr>
<th>@attr.Name</th>
<td>
@switch (attr.Value)
{
case string:
case int:
case double:
@attr.Value
break;
case HtmlString html:
@await Html.FromWysiwygAsync(html)
break;
case bool isTrue:
@(isTrue ? "Yes" : "No")
break;
case IEnumerable<string> list:
<ul>
@foreach (var item in list)
{
<li>@item</li>
}
</ul>
break;
case EntityRef<Asset> asset:
@await Component.InvokeAsync(typeof(ConfinityPicture),
new ConfinityPictureModel(await AssetService.GetImageAsset(asset)))
break;
case IEnumerable<EntityRef<Asset>> assets:
foreach (var asset in assets)
{
@await Component.InvokeAsync(typeof(ConfinityPicture),
new ConfinityPictureModel(await AssetService.GetImageAsset(asset)))
}
break;
case LinkModel link:
<a confinity-link="link"></a>
break;
case IEnumerable<LinkModel> links:
<ul>
@foreach (var link in links)
{
<li>
<a confinity-link="link"></a>
</li>
}
</ul>
break;
default:
<text>unknown type (@attr.Value?.GetType())</text>
break;
}
@attr.Unit
</td>
</tr>
}
</table>
}
}
else
{
<p>Product not found</p>
}
Attribute value types
The following return types are possible for a AttributeValueModel.Value:
booldoubleintstringHtmlStringLinkModelEntityRef<Asset>EntityRef<T>(where T is one of your registered entities)IEnumerable<double>IEnumerable<int>IEnumerable<string>IEnumerable<LinkModel>IEnumerable<EntityRef<Asset>>IEnumerable<EntityRef<T>(where T is one of your registered entities)>
Reference Entities From a Product
You might want to reference your entities from a product. For this case, we have built the product attribute type "Reference (single)" and "References (multiple)", which allows the author to select an entity, which then can be referenced by a product. But first, you have to register the entity in order an author can select it.
To do so, you have to register the entity via .Net's Options API and add your configuration to the list EntityReferenceTypes in ConfinityProductsOptions like in the following example.
services.Configure<ConfinityProductsOptions>(options =>
{
options.EntityReferenceTypes.Add(
new EntityReferenceOption<Page>
{
LabelExpression = entity => entity.Name + " " + entity.Slug,
TypeLabel = "Articles"
});
});