Dev GuideAPI Reference
Dev GuideAPI ReferenceUser GuideLegal TermsGitHubDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

Custom widget attributes

Describes how to include custom attributes that the end user can access and alter based on the widget in Optimizely Configured Commerce.

After creating a custom widget, it is likely that you will 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(drop-downContentFieldAttribute). This is required to make use of the existing html template, without it a new html template would be required.

public class CountrySelector : drop-downContentFieldAttribute
{
    public override Type GenericType => typeof(drop-downContentFieldAttribute);
 
    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. 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 : drop-downContentFieldAttribute
{
    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. This razor view needs to be an embedded resource. By default the extensions project will embed all razor views.

This example is a copy of the drop-down.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); }