Loading...
Area: Episerver B2B Commerce

Custom widget attributes in Classic

Recommended reading 

After creating a custom widget, it is likely that you'll also want to include custom attributes that the end user can access and alter as needed based on the widget.

ContentFieldAttributes

ContentFieldAttributes can be used to customize the display/editing of a property on a widget. An example of this is adding a Country Selection ability to a widget.

First create a new class with the following content. In this example we are inheriting from an existing attribute. An important thing to note is that we override GenericType to return typeof(DropDownContentFieldAttribute). This is required to make use of the existing html template, without it a new html template would be required

public class CountrySelector : DropDownContentFieldAttribute
{
    public override Type GenericType => typeof(DropDownContentFieldAttribute);
 
    public CountrySelector() : base(new string[0])
    {
        var countries = DependencyLocator.Current.GetInstance<IUnitOfWorkFactory>().GetUnitOfWork().GetRepository<Country>().GetTable().OrderBy(o => o.Name).ToList();
        this.Options = countries.Select(o => new KeyValuePair<string, string>(o.Id.ToString(), o.Name)).ToArray();
    }
}

If a custom html template is needed for our new attribute, then the Template property can be set in our new class. In order to make sure of a razor view from the extensions project, this value needs to start with "~/Extensions/" followed by the path to the view inside of the project.

public class CountrySelector : DropDownContentFieldAttribute
{
    public CountrySelector() : base(new string[0])
    {
        this.Template = "~/Extensions/Views/ContentItemFields/CountrySelector.cshtml";
 
        var countries = DependencyLocator.Current.GetInstance<IUnitOfWorkFactory>().GetUnitOfWork().GetRepository<Country>().GetTable().OrderBy(o => o.Name).ToList();
        this.Options = countries.Select(o => new KeyValuePair<string, string>(o.Id.ToString(), o.Name)).ToArray();
    }
}

Then in the extensions project a razor view needs to exist at Views/ContentItemFields/CountrySelector.cshtml. By default, the extensions project will embed all razor views, which is required for the view to be available to Epi B2B Commerce.

This example is a copy of the DropDown.cshtml view, with the @model declaration modified to use our new Extensions.CountrySelector

@using Insite.ContentLibrary.ContentFields
@using Insite.WebFramework.ContentAdmin.Models.ContentItems
 
@model EditContentFieldModel<Extensions.CountrySelector>
 
<label for="@Model.FieldName">
    @Model.DisplayName
    @if (Model.ContentFieldAttribute.IsRequired)
    {
        <span class="required">(required)</span>
    }
 
    @Html.Partial("ContentItemFields/_ContextDisplay", Model.ContentItemFieldModel)
</label>
<span data-valmsg-replace="true" data-valmsg-for="@(Model.FieldName)"></span>
<select id="@Model.FieldName" name="@Model.FieldName" @if (Model.ContentFieldAttribute.IsRequired) { <text> data-val="true" data-val-required="Value is required" </text> }>
    <option value="">Select Value</option>
    @foreach (var value in Model.ContentFieldAttribute.Options)
    {
        <option value="@value.Key" @(Model.GetValue().ToString() == value.Key ? "selected" : "")>@value.Value</option>
    }
</select>

To make use of the new ContentFieldAttribute, add a new property to a custom widget. Then include your new attribute on the property. When editing this widget, the CountrySelector will be used.

[CountrySelector]
public string SelectedCountry
{
    get { return this.GetValue("SelectedCountry", string.Empty, FieldType.General); }
    set { this.SetValue("SelectedCountry", value, FieldType.General); }

 

Do you find this information helpful? Please log in to provide feedback.

Last updated: Dec 11, 2020

Recommended reading