Filtering Sitefinity DynamicContentView on the frontend

Filtering Sitefinity DynamicContentView on the frontend

April 03, 2013 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.

The scenario for today's blog post is a pretty straightforward one - as a website developer I'd like to offer my frontend users a mechanism for filtering the list of Dynamic Module items by certain criteria.

To represent the idea better, let's say we'll be dealing with Offices - we're an international company that has offices around the globe. 

Handling this type of scenario with Sitefinity Module Builder takes not more than 5 minutes - the time in which I defined my new module, added some fields to specify the office Title, Country, City, ZipCode, PhoneNumber etc. fields.

Once we've created the module our next step is to deliver the filtering functionality.

For this purpose we're going to inherit from DynamicContentView, which is the type of the widget ModuleBuilder creates for displaying your new module content:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Telerik.Sitefinity.DynamicModules.Web.UI.Frontend;
namespace SitefinityWebApp.OfficesModule
{
    public class DynamicContentViewCustom : DynamicContentView
    {
        protected DynamicContentViewMaster MasterViewControl
        {
            get
            {
                if (this.masterViewControl == null)
                {
                    this.masterViewControl = new DynamicContentViewMasterCustom(this.DynamicManager);
                }
                return this.masterViewControl;
            }
            set
            {
                this.masterViewControl = value;
            }
        }
        protected override void InitializeMasterView()
        {
            if (this.HasValidRelatedDataConfiguration && this.RelatedItemsIds != null)
            {
                this.MasterViewControl.SourceItemsIds = this.RelatedItemsIds;
            }
            this.MasterViewControl.TemplateKey = string.IsNullOrEmpty(this.MasterViewDefinition.TemplateKey) ? this.DefaultMasterTemplateKey : this.MasterViewDefinition.TemplateKey;
            this.MasterViewControl.DynamicContentType = this.DynamicContentType;
            this.MasterViewControl.MasterViewDefinition = this.MasterViewDefinition;
            this.MasterViewControl.UrlEvaluationMode = this.UrlEvaluationMode;
            this.MasterViewControl.UrlKeyPrefix = this.UrlKeyPrefix;
            this.Controls.Add(this.MasterViewControl);
        }
        
        private DynamicContentViewMaster masterViewControl;
    }
}
-------------------------------------------------------------------------------------------------------------------------------
NOTE:
After Sitefinity 6.1 the DynamicContentViewMaster class now has a Host property which allows you to easily access the DynamicContentView (which is the Host) for its master/details view. This change requires you to modify the above code slightly, so if you are using Sitefinity 6.1 or higher version of our product, please use this sample instead:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Telerik.Sitefinity.DynamicModules.Web.UI.Frontend;
namespace SitefinityWebApp.OfficesModule
{
    public class DynamicContentViewCustom : DynamicContentView
    {
        protected DynamicContentViewMaster MasterViewControl
        {
            get
            {
                if (this.masterViewControl == null)
                {
                    this.masterViewControl = new DynamicContentViewMasterCustom(this.DynamicManager);
                    this.masterViewControl.Host = this;
                }
                return this.masterViewControl;
            }
            set
            {
                this.masterViewControl = value;
            }
        }
        protected override void InitializeMasterView()
        {
            if (this.HasValidRelatedDataConfiguration && this.RelatedItemsIds != null)
            {
                this.MasterViewControl.SourceItemsIds = this.RelatedItemsIds;
            }
            this.MasterViewControl.TemplateKey = string.IsNullOrEmpty(this.MasterViewDefinition.TemplateKey) ? this.DefaultMasterTemplateKey : this.MasterViewDefinition.TemplateKey;
            this.MasterViewControl.DynamicContentType = this.DynamicContentType;
            this.MasterViewControl.MasterViewDefinition = this.MasterViewDefinition;
            this.MasterViewControl.UrlEvaluationMode = this.UrlEvaluationMode;
            this.MasterViewControl.UrlKeyPrefix = this.UrlKeyPrefix;
            this.Controls.Add(this.MasterViewControl);
        }
         
        private DynamicContentViewMaster masterViewControl;
    }
}
-------------------------------------------------------------------------------------------------------------------------------
As you can see from the above sample, our new class overrides just one method of the base DynamicContentView, namely InitializeMasterView(). In InitializeMasterView() we are able to substitute the default MasterViewControl with our custom one - DynamicContentViewMasterCustom, defined above.

Our DynamicContentViewMasterCustom is a new class, inheriting from DynamicContentViewMaster, and will have a customized template that will facilitate the UI for filtering on the frontend.

For the sake of this example I've copied the default template our new module has created (you can access this from Design->WidgetTemplates-> YourModule list) and added the desired controls to it:
<%@ Control Language="C#" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.PublicControls.BrowseAndEdit" Assembly="Telerik.Sitefinity" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.ContentUI" Assembly="Telerik.Sitefinity" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.Comments" Assembly="Telerik.Sitefinity" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.Fields" Assembly="Telerik.Sitefinity" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI" Assembly="Telerik.Sitefinity" %>
<%@ Register TagPrefix="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %>
<span>City</span>
<br />
<asp:TextBox ID="cityTextBox" runat="server" />
<br />
<span>Country</span>
<br />
<asp:TextBox ID="countryTextBox" runat="server" />
<br />
<span>ZipCode</span>
<br />
<asp:TextBox ID="zipCodeTextBox" runat="server" />
<br />
<asp:Button ID="searchBtn" Text="Search" runat="server" />
<telerik:RadListView ID="dynamicContentListView" ItemPlaceholderID="ItemsContainer" runat="server" EnableEmbeddedSkins="false" EnableEmbeddedBaseStylesheet="false">
    <LayoutTemplate>
        <ul class="sfitemsList sfitemsListTitleDateTmb">
            <asp:PlaceHolder ID="ItemsContainer" runat="server" />
        </ul>
    </LayoutTemplate>
    <ItemTemplate>
        <li class="sfitem sfClearfix">
            <h2 class="sfitemTitle">
                <sf:DetailsViewHyperLink ID="DetailsViewHyperLink" TextDataField="Title" runat="server" />
            </h2>
            <sf:FieldListView ID="PublicationDate" runat="server" Format="{PublicationDate.ToLocal():MMM d, yyyy, HH:mm tt}" WrapperTagName="div" WrapperTagCssClass="sfitemPublicationDate" />
        </li>
    </ItemTemplate>
</telerik:RadListView>
<sf:Pager ID="pager" runat="server"></sf:Pager>
<asp:PlaceHolder ID="socialOptionsContainer" runat="server"></asp:PlaceHolder>


In the DynamicContentViewMasterCustom we can now reference these controls, using the this.Container.GetControl<T>() approach:
#region Control References
      protected virtual TextBox CityTextBox
      {
          get
          {
              return this.Container.GetControl<TextBox>("cityTextBox", true);
          }
      }
      protected virtual TextBox CountryTextBox
      {
          get
          {
              return this.Container.GetControl<TextBox>("countryTextBox", true);
          }
      }
      protected virtual TextBox ZipCodeTextBox
      {
          get
          {
              return this.Container.GetControl<TextBox>("zipCodeTextBox", true);
          }
      }
      protected virtual Button SearchButton
      {
          get
          {
              return this.Container.GetControl<Button>("searchBtn", true);
          }
      }
      #endregion

and then subscribe to the Click event of the SearchButton by overriding the base InitializeControls method:
protected override void InitializeControls(Telerik.Sitefinity.Web.UI.GenericContainer container)
        {
            SearchButton.Click += SearchButton_Click;
            base.InitializeControls(container);
        }

our final step is to implement the actual filtering of the DataSource according to the user input:

void SearchButton_Click(object sender, EventArgs e)
        {
            var dataSource = ((IEnumerable<DynamicContent>)this.DynamicContentListView.DataSource);
            if (!this.CityTextBox.Text.IsNullOrEmpty())
                dataSource = dataSource.Where(itm => itm.GetValue(cityFieldName).ToString().Contains(CityTextBox.Text));
            if (!this.CountryTextBox.Text.IsNullOrEmpty())
                dataSource = dataSource.Where(itm => itm.GetValue(countryFieldName).ToString().Contains(CountryTextBox.Text));
               
            if (!this.ZipCodeTextBox.Text.IsNullOrEmpty())
                   dataSource = dataSource.Where(itm => itm.GetValue(zipFieldName).ToString().Contains(ZipCodeTextBox.Text));
            this.DynamicContentListView.DataSource = dataSource.ToList();
        }

as you can see, DynamicContentListView already has its DataSource set for us, so we can access it, and apply our filtering directly.

Once you're done the last step is registering your new widget. Go to App_Data/Sitefinity/Configuration/ToolboxesConfig.config and find the entry for your module's widget. It should look  like this:
<add enabled="True" type="Telerik.Sitefinity.DynamicModules.Web.UI.Frontend.DynamicContentView, Telerik.Sitefinity" title="OfficesCustom" cssClass="sfNewsViewIcn" moduleName="Offices" DynamicContentTypeName="Telerik.Sitefinity.DynamicTypes.Model.Offices.Office" DefaultMasterTemplateKey="3fc7803a-47fd-6966-a5dc-ff0000f47b12" DefaultDetailTemplateKey="40c7803a-47fd-6966-a5dc-ff0000f47b12" visibilityMode="None" name="Telerik.Sitefinity.DynamicTypes.Model.Offices.Office" />

Change the type parameter to match the type of your custom DynamicContentView:

<add enabled="True" type="SitefinityWebApp.OfficesModule.DynamicContentViewCustom" title="OfficesCustom" cssClass="sfNewsViewIcn" moduleName="Offices" DynamicContentTypeName="Telerik.Sitefinity.DynamicTypes.Model.Offices.Office" DefaultMasterTemplateKey="3fc7803a-47fd-6966-a5dc-ff0000f47b12" DefaultDetailTemplateKey="40c7803a-47fd-6966-a5dc-ff0000f47b12" visibilityMode="None" name="Telerik.Sitefinity.DynamicTypes.Model.Offices.Office" />

Save the file and restart your application - you'll now be able to drop the widget on any Sitefinity page and enjoy the results.

You can find the complete implementation of our DynamicContentViewMasterCustom along with the custom template and DynamicContentViewCustom attached to this post - OfficesModule.

For your convenience please find here a short video demonstrating the final results as well.

I hope you enjoyed reading about this simple functionality, and the ease of achieving it with Sitefinity. 
progress-logo

The Progress Guys

View all posts from The Progress Guys 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
 
 
Latest Stories in
Your Inbox
Subscribe
More From Progress
d12fcc0bdb669b804e7f71198c9619a7
5 Questions Automakers Should Ask to Improve Asset Uptime
Download Whitepaper
 
SF_MQ_WCM
2018 Gartner Magic Quadrant Web Content Management (WCM)
Download Whitepaper
 
What-Serverless-Means-For-Enterprice-Apps-Kinvey
What Serverless Means for Enterprise Apps
Watch Webinar