Tutorial: Create custom sidebar widgets
This tutorial demonstrates how you can extend a built-in command widget to add new functionality to it to implement a custom filter. Use the ProductsCatalogSample
module that is distributed with the Sitefinity SDK
Implementing the custom widget
Extend the DynamicCommandWidget
class which allows you to bind a datasource such as collection of categories and display them on the side bar. Then, you can filter for your items based on desired filter expression.
Implement the server-side class
First, create the custom widget class. The difference with the built-in class is that is has an extra JavaScript file reference added to execute the custom logic:
using System;
using System.Collections.Generic;
using System.Web.UI;
using Telerik.Sitefinity.Web.UI.Backend.Elements.Widgets;
namespace ProductCatalogSample.Web.UI
{
class CustomDynamicCommandWidget : DynamicCommandWidget
{
protected override Type ResourcesAssemblyInfo
{
get
{
return typeof(DynamicCommandWidget);
}
}
public override IEnumerable<
System.Web.UI.ScriptReference
> GetScriptReferences()
{
var widgetInterfaceScript = new ScriptReference
{
Assembly = typeof(IWidget).Assembly.FullName,
Name = Scripts.IWidget
};
var commandWidgetInterfaceScript = new ScriptReference
{
Assembly = typeof(DynamicCommandWidget).Assembly.FullName,
Name = Scripts.ICommandWidget
};
var commandWidgetScript = new ScriptReference
{
Assembly = typeof(DynamicCommandWidget).Assembly.FullName,
Name = Scripts.DynamicCommandWidget
};
//register the custom script
var customCommandWidgetScript = new ScriptReference
{
Assembly = typeof(CustomDynamicCommandWidget).Assembly.FullName,
Name = Scripts.CustomDynamicCommandWidget
};
return new ScriptReference[] { widgetInterfaceScript, commandWidgetInterfaceScript, commandWidgetScript, customCommandWidgetScript };
}
internal struct Scripts
{
public const string IWidget = "Telerik.Sitefinity.Web.SitefinityJS.UI.IWidget.js";
public const string ICommandWidget = "Telerik.Sitefinity.Web.SitefinityJS.UI.ICommandWidget.js";
public const string DynamicCommandWidget = "Telerik.Sitefinity.Web.UI.Backend.Elements.Widgets.Scripts.DynamicCommandWidget.js";
public const string CustomDynamicCommandWidget = "ProductCatalogSample.Web.UI.CustomDynamicCommandWidget.js";
}
}
}
Implement the client-side component
After you have implemented the server-side class, you need to add the custom filtering functionality to the client-side component (CustomDynamicCommandWidget.js
). There is a built-in method that handles item commands that you can override in the following way:
/// <
reference
name
=
"MicrosoftAjax.js"
/>
/// <
reference
name
=
"Telerik.Sitefinity.Resources.Scripts.jquery-1.4.2-vsdoc.js"
assembly
=
"Telerik.Sitefinity.Resources"
/>
Type.registerNamespace("ProductCatalogSample.Web.UI");
ProductCatalogSample.Web.UI.CustomDynamicCommandWidget = function (element) {
ProductCatalogSample.Web.UI.CustomDynamicCommandWidget.initializeBase(this, [element]);
}
ProductCatalogSample.Web.UI.CustomDynamicCommandWidget.prototype =
{
initialize: function () {
ProductCatalogSample.Web.UI.CustomDynamicCommandWidget.callBaseMethod(this, "initialize");
},
dispose: function () {
ProductCatalogSample.Web.UI.CustomDynamicCommandWidget.callBaseMethod(this, "dispose");
},
_binderCommandHandler: function (sender, args) {
var commandEventArgs = new Telerik.Sitefinity.UI.CommandEventArgs(this._commandName, { 'filterExpression': this.getCategoriesFilterExpression() });
//send a filtering command ot our grid view to fitler by the selected checkboxes
//if there are no selected checkboxes the filtering expression will be empty string showing all items
var h = this.get_events().getHandler('command');
if (h) h(this, commandEventArgs);
},
getCategoriesFilterExpression: function () {
var selectedItems = jQuery("input.sf_binderCommand_filterByCategory:checked");
var expression = '';
//get selected checkboxes and cosntruct the filter expression
if (selectedItems.length > 0) {
for (var i = 0; i < selectedItems.length; i++) {
if (i == 0)
expression = expression + 'Category.Contains((' + selectedItems[i].value + '))';
else
expression = expression + 'OR Category.Contains((' + selectedItems[i].value + '))';
}
}
return expression;
}
}
ProductCatalogSample.Web.UI.CustomDynamicCommandWidget.registerClass("ProductCatalogSample.Web.UI.CustomDynamicCommandWidget", Telerik.Sitefinity.Web.UI.Backend.Elements.Widgets.DynamicCommandWidget, Telerik.Sitefinity.UI.ICommandWidget, Telerik.Sitefinity.UI.IWidget);
Implement grid view extension script
Because you are building a custom type widget, you need to explicitly tell the grid view in the backend items list to bind the widget with the datasource (CustomDynamicCommandWidgetExtensionScript.js
). You need to get the sidebar and find the widget. Then bind it in the following way:
function OnMasterViewLoaded(sender, args) {
if (sender.get_sidebar()) {
var widgetsInSidebar = sender.get_sidebar()._widgets;
if (widgetsInSidebar) {
for (var i = 0; i < widgetsInSidebar.length; i++) {
if (Object.getTypeName(widgetsInSidebar[i]) == "ProductCatalogSample.Web.UI.CustomDynamicCommandWidget") {
widgetsInSidebar[i].dataBind();
}
}
}
}
}
Register scripts with the assembly
When you are done with the client-side component and the extension script, you need to register them as embedded resources in the AssemblyInfo
class of the code library project in the following way:
[assembly: WebResource("ProductCatalogSample.Web.UI.CustomDynamicCommandWidget.js","text/javascript")]
[assembly: WebResource("ProductCatalogSample.Web.UI.CustomDynamicCommandWidgetExtensionScript.js", "text/javascript")]
Set the custom module to use the command widget
All configurations of the backend of your modules are done through the module's definition class. You need to register the extension script and the custom command widget. Because you are working with the ProductsCatalogSample
project, you need to edit the ProductsDefinitions
class in the following way:
Register the extension script
This is done in the DefineProductsBackendContentView
method where the grid view is defined:
#region external scripts
var scripts = new Dictionary<
string
, string>();
scripts.Add(
string.Format("{0}, {1}",
ProductsDefinitions.CustomDynamicCommandWidgetExtensionScript,typeof(ProductsModule).Assembly.FullName),
"OnMasterViewLoaded");
productsGridView.ExternalClientScripts = scripts;
#endregion
public const string CustomDynamicCommandWidgetExtensionScript = "ProductCatalogSample.Web.UI.CustomDynamicCommandWidgetExtensionScript.js";
Configure the custom dynamic command widget
You need to substitute the built-in dynamic command widget definition for filtering by categories with the custom one. Find where the dynamic command widget for categories is registered in the ProductDefinitions
class and amend it in the following way:
var categoryFilterWidget = new DynamicCommandWidgetElement(categoryFilterSection.Items)
{
Name = "CategoryFilter",
CommandName = "filter",
PageSize = 10,
WidgetType = typeof(CustomDynamicCommandWidget),
IsSeparator = false,
BindTo = BindCommandListTo.HierarchicalData,
BaseServiceUrl = String.Format("~/Sitefinity/Services/Taxonomies/HierarchicalTaxon.svc/{0}/", TaxonomyManager.CategoriesTaxonomyId),
ChildItemsServiceUrl = "~/Sitefinity/Services/Taxonomies/HierarchicalTaxon.svc/subtaxa/",
PredecessorServiceUrl = "~/Sitefinity/Services/Taxonomies/HierarchicalTaxon.svc/predecessor/",
ClientItemTemplate = @" <
input
type
=
'checkbox'
class
=
'sf_binderCommand_filterByCategory'
sys:value
=
'{{ Id }}'
>{{ Title }}</
input
> <
span
class
=
'sfCount'
>({{ItemsCount}})</
span
>"
};
Build the project.