Creating a Widget provider
There are many ways to display or inject content in Smartstore. One of the methods is to use a Widget. Following the tutorial Adding tabs tutorial, you'll be adding a widget to your project.
Implementing the IActivatableWidget
Using the module from the Adding tabs tutorial, we'll start with the Module.cs
file. You'll need to add the interface IActivatableWidget
to the implementation.
public class Module : ModuleBase, IConfigurable, IActivatableWidget
This will force you to implement the following two Methods:
public Widget GetDisplayWidget(string widgetZone, object model, int storeId)
public string[] GetWidgetZones()
GetWidgetZones
is a string array containing every widget zone we want to access.
public string[] GetWidgetZones()
{
return new string[] { "target_widget_zone_name" };
}
In this tutorial we'll be using the productdetails_pictures_top
widget zone. It is placed above the product picture when using the Frontend.
A simple implementation for GetDisplayWidget
would be
public Widget GetDisplayWidget(string widgetZone, object model, int storeId)
=> new ComponentWidget(typeof(HelloWorldViewComponent), new {widgetZone, model, storeId});
which creates a ComponentWidget
for all widget zones we specified in GetWidgetZones
. Your code should look something like this:
public class Module : ModuleBase, IConfigurable, IActivatableWidget
{
// ...
public Widget GetDisplayWidget(string widgetZone, object model, int storeId)
=> new ComponentWidget(typeof(HelloWorldViewComponent), new {widgetZone, model, storeId});
public string[] GetWidgetZones()
=> new string[] { "productdetails_pictures_top" };
// ...
}
Create the ViewComponentModel
For the widget to access MyTabValue
from the previous tutorial, you'll need to create a new model.
Right click on the Models folder in the Solution Explorer.
Place a new class called
ViewComponentModel.cs
in this folder.
Then add the following lines:
using Smartstore.Web.Modelling;
namespace MyOrg.HelloWorld.Models
{
public class ViewComponentModel : ModelBase
{
public string MyTabValue { get; set; }
}
}
Adding the ViewComponent
Right click on the project in the Solution Explorer.
Add a new folder. According to our guidelines we call it Components.
Place a new class called HelloWorldViewComponent.cs in this folder.
This class implements SmartViewComponent
.
public class HelloWorldViewComponent : SmartViewComponent
To use the database context, add it to the constructor using dependency injection.
private readonly SmartDbContext _db;
public HelloWorldViewComponent(SmartDbContext db)
{
_db = db;
}
Next you'll add the InvokeAsync
method. It is called each time the widget zones specified in GetWidgetZones
is about to get rendered. The model is passed from GetDisplayWidget
.
public async Task<IViewComponentResult> InvokeAsync(string widgetZone, object model)
In case you're handling multiple widget zones and need to differentiate between them, you might add an if- or a switch-block for widgetZone
. If you just want to make sure that your widget isn't displaying anything, when it is not supposed to, add the following lines:
if (widgetZone != "productdetails_pictures_top")
{
return Empty();
}
After checking whether the correct model is being used, you fetch the product from the database and get the specified MyTabValue
.
if (model.GetType() != typeof(ProductDetailsModel))
{
return Empty();
}
var productModel = (ProductDetailsModel)model;
var product = await _db.Products.FindByIdAsync(productModel.Id);
var attributeValue = product.GenericAttributes.Get<string>("HelloWorldMyTabValue");
And finally you create the ViewComponentModel
and return the View.
var viewComponentModel = new ViewComponentModel
{
MyTabValue = attributeValue
};
return View(viewComponentModel);
For you to use ProductDetailsModel
, add these lines to you project file:
<ItemGroup>
<ProjectReference Include="..\..\Smartstore.Web\Smartstore.Web.csproj">
<Private>False</Private>
<CopyLocal>False</CopyLocal>
<CopyLocalSatelliteAssemblies>False</CopyLocalSatelliteAssemblies>
</ProjectReference>
</ItemGroup>
The final code looks like this:
public class HelloWorldViewComponent : SmartViewComponent
{
private readonly SmartDbContext _db;
public HelloWorldViewComponent(SmartDbContext db)
{
_db = db;
}
public async Task<IViewComponentResult> InvokeAsync(string widgetZone, object model)
{
if (widgetZone != "productdetails_pictures_top")
{
return Empty();
}
if (model.GetType() != typeof(ProductDetailsModel))
{
return Empty();
}
var productModel = (ProductDetailsModel)model;
var product = await _db.Products.FindByIdAsync(productModel.Id);
var attributeValue = product.GenericAttributes.Get<string>("HelloWorldMyTabValue");
var viewComponentModel = new ViewComponentModel
{
MyTabValue = attributeValue
};
return View(viewComponentModel);
}
}
Adding the cacheable routes
You must add this code to your module if your ViewComponent should be cacheable. For more information see output cache.
Right click on the project in the Solution Explorer.
Place a new class called CacheableRoutes.cs in this folder.
Then add these lines:
using Smartstore.Core.OutputCache;
namespace MyOrg.HelloWorld
{
internal sealed class CacheableRoutes : ICacheableRouteProvider
{
public int Order => 0;
public IEnumerable<string> GetCacheableRoutes()
{
return new string[]
{
"vc:MyOrg.HelloWorld/HelloWorld"
};
}
}
}
Adding the View
Right click on the Views folder of your module in the Solution Explorer.
Add a new folder. According to the guidelines we call it Shared/Components/HelloWorld.
Place a new Razor View called
Default.cshtml
in this folder.
Add the following lines for a simple output:
@model ViewComponentModel
@{
Layout = "";
}
<span>Widget content: @Model.MyTabValue</span>
Conclusion
Now you should be able to define a property in your product catalog and see it displayed above the product picture.
Don't forget to activate your widget!
Go to the Smartstore admin settings
Navigate to CMS / Widgets
You should see your widget listed. Press Activate.
In this tutorial you built a widget using the IActivatableWidget
interface and specified your widget zones. You created a ViewComponent
and bound it to different widget zones. Hopefully this will get you started with widgets and enable you to build more complex modules.
Last updated
Was this helpful?