Filtering dynamic items by taxonomies in the backend grid

Filtering dynamic items by taxonomies in the backend grid

Posted on September 03, 2012 0 Comments

The content you're reading is getting on in years
This post is on the older side and its content may be out of date.
Be sure to visit our blogs homepage for our latest news, updates and information.

Based on Radoslav Georgiev blog post about adding custom widget to the sidebar here I am going to add some additional modification to enable filtering by taxonomies in the backend grid for modules built using the Module Builder.

First we need to extend the DynamicCommandWidget which I am going to bind to a collection of categories and display them in the sidebar. However this can be easily modified to work with any taxonomies, even custom ones.

To get started create a new folder in SitefinityBaseWebApp project named CategoriesDynamicCommandWidget. This folder will hold the server code and client scripts needed for the new widget. Here I am adding CategoriesDynamicCommandWidget.cs class that extends DynamicCommandWidget and register additional JavaScript reference:


using System;
using System.Collections.Generic;
using System.Web.UI;
using Telerik.Sitefinity.Web.UI.Backend.Elements.Widgets;
 
namespace SitefinityWebApp.CategoriesDynamicCommandWidget
{
    public class CategoriesDynamicCommandWidget : 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 CategoriesCommandWidgetScript = new ScriptReference
            {
                Assembly = typeof(CategoriesDynamicCommandWidget).Assembly.FullName,
                Name = Scripts.CategoriesDynamicCommandWidget
            };
            return new ScriptReference[] { widgetInterfaceScript, commandWidgetInterfaceScript, commandWidgetScript, CategoriesCommandWidgetScript };
        }
          
        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 CategoriesDynamicCommandWidget = "SitefinityWebApp.CategoriesDynamicCommandWidget.Scripts.CategoriesDynamicCommandWidget.js";
        }
    }
}

Now we are going to add the client side code which will simply override a built in method that handles item commands – in our case filtering by categories. Add a folder named Scripts under CategoriesDynamicCommandWidget and create a new JavaScript file CategoriesDynamicCommandWidget.js and place the following code in  it:

/// <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");
 
SitefinityWebApp.CategoriesDynamicCommandWidget.CategoriesDynamicCommandWidget = function (element) {
    SitefinityWebApp.CategoriesDynamicCommandWidget.CategoriesDynamicCommandWidget.initializeBase(this, [element]);
}
 
SitefinityWebApp.CategoriesDynamicCommandWidget.CategoriesDynamicCommandWidget.prototype =
{
    initialize: function () {
        SitefinityWebApp.CategoriesDynamicCommandWidget.CategoriesDynamicCommandWidget.callBaseMethod(this, "initialize");
    },
 
    dispose: function () {
        SitefinityWebApp.CategoriesDynamicCommandWidget.CategoriesDynamicCommandWidget.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 filter 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 construct 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;
    }
}
 
SitefinityWebApp.CategoriesDynamicCommandWidget.CategoriesDynamicCommandWidget.registerClass("SitefinityWebApp.CategoriesDynamicCommandWidget.CategoriesDynamicCommandWidget", Telerik.Sitefinity.Web.UI.Backend.Elements.Widgets.DynamicCommandWidget, Telerik.Sitefinity.UI.ICommandWidget, Telerik.Sitefinity.UI.IWidget);

Since we are building a custom type widget we need to explicitly tell the grid view in our backend items list to bind the widget with our datasource. We need to get the sidebar, find our widget and then bind it. Add a CategoriesDynamicCommandWidgetExtensionScript.js file to the Scripts folder and place the following code in it:


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]) == "SitefinityWebApp.CategoriesDynamicCommandWidget") {
                    widgetsInSidebar[i].dataBind();
                }
            }
        }
    }
}

We also need to register the .js files in the assembly info. Don’t forget to set the Build Action for them to Embedded Resource.

[assembly: WebResource("SitefinityWebApp.CategoriesDynamicCommandWidget.Scripts.CategoriesDynamicCommandWidget.js", "text/javascript")]
[assembly: WebResource("SitefinityWebApp.CategoriesDynamicCommandWidget.Scripts.CategoriesDynamicCommandWidgetExtensionScript.js", "text/javascript")]

Build the project and open Sitefinity administration to add some additional settings. First make sure that you have added a custom module with a categories field. Then navigate to Administration -> Settings -> Advanced -> DynamicModules -> Controls -> Telerik.Sitefinity.DynamicTypes.Model.MyModule.MyContentTypeBackendDefinition -> Views -> MyContentTypeBackendList -> Sidebar -> Sections. Create a new section. Populate the fields as follow:

Name: Category
Title: ItemsByCategory
WrapperTagId: categoryFilterSection
CssClass: sfFilterBy sfSeparator
Visible: True

In the items section create a new DynamicCommandWidgetElement. Enter the following values:

Web service Url: ~/Sitefinity/Services/Taxonomies/HierarchicalTaxon.svc/e5cd6d69-1543-427b-ad62-688a99f5e7d4/ 
Child items service URL: ~/Sitefinity/Services/Taxonomies/HierarchicalTaxon.svc/subtaxa/
Predecessor service URL: ~/Sitefinity/Services/Taxonomies/HierarchicalTaxon.svc/predecessor/
Bind to: HierarchicalData
Client item template: <input type='checkbox' class='sf_binderCommand_filterByCategory' sys:value='{{ Id }}'>{{ Title }}</input> <span class='sfCount'>({{ItemsCount}})</span>
Command name: filter
Name: CategoryFilter
Type: SitefinityWebApp.CategoriesDynamicCommandWidget.CategoriesDynamicCommandWidget

Note that the id of the end of the web service Url is the id of the categories taxonomy and it is unique for every application. The easiest way to find that guid is to add categories widget to a page, edit the widget, delete the value in TaxonomyId field and save then the guids of all of the taxonomies in your application will show up.

There is one last thing left to be done. We need to register our extension script. Go back to MyContentTypeBackendList and expand the Scripts section. Create new one and for Script location set the path to your extension file and the namespace. In our case its value is:

SitefinityWebApp.CategoriesDynamicCommandWidget.Scripts.CategoriesDynamicCommandWidgetExtensionScript.js, SitefinityWebApp

For Name of the load method enter OnMasterViewLoaded and save. 

Restart your application and navigate to your content type items grid. In the sidebar you should see the categories and when you select some of the the grid will be updated.

progress-logo

The Progress Team

View all posts from The Progress Team on the Progress blog. Connect with us about all things application development and deployment, data integration and digital business.

Comments

Comments are disabled in preview mode.
Topics

Sitefinity Training and Certification Now Available.

Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.

Learn More
Latest Stories
in Your Inbox

Subscribe to get all the news, info and tutorials you need to build better business apps and sites

Loading animation