Create a Custom Designer with a Categories Filter
I am creating a custom designer for a widget that will display News content items among other things.
I would like to allow filtering of News content items by Category (as the normal News widget does). Is there any documentation describing how to do this?
So far I've identified some code to put in the designer template:
<%@ Register Assembly="Telerik.Sitefinity" TagPrefix="sitefinity" Namespace="Telerik.Sitefinity.Web.UI" %><%@ Register Assembly="Telerik.Sitefinity" TagPrefix="designers" Namespace="Telerik.Sitefinity.Web.UI.ControlDesign" %><%@ Register Assembly="Telerik.Sitefinity" TagPrefix="sfFields" Namespace="Telerik.Sitefinity.Web.UI.Fields" %><sfFields:FormManager id="formManager" runat="server" /><div> <h2> <asp:Literal ID="choicesTitle" runat="server" Text="<%$Resources:Labels, WhichNewsToDisplay %>" /></h2> <ul class="sfRadioList"> <li> <asp:RadioButton runat="server" ID="contentSelect_AllItems" Checked="true" GroupName="ContentSelection" Text="<%$Resources:Labels, AllPublishedNews %>" /> </li> <li> <asp:RadioButton runat="server" ID="contentSelect_SimpleFilter" GroupName="ContentSelection" Text="<%$Resources:Labels, SelectionOfNews %>" /> <div id="selectorsPanel"> <designers:FilterSelector ID="filterSelector" runat="server" AllowMultipleSelection="true" ItemsContainerTag="ul" ItemTag="li" ItemsContainerCssClass="sfCheckListBox sfExpandedPropertyDetails" DisabledTextCssClass="sfTooltip"> <Items> <designers:FilterSelectorItem ID="FilterSelectorItem1" runat="server" Text="<%$Resources:Labels, ByCategories %>" GroupLogicalOperator="AND" ItemLogicalOperator="OR" ConditionOperator="Contains" QueryDataName="Categories" QueryFieldName="Category" QueryFieldType="System.Guid"> <SelectorResultView> <sitefinity:HierarchicalTaxonSelectorResultView ID="HierarchicalTaxonSelectorResultView1" runat="server" WebServiceUrl="~/Sitefinity/Services/Taxonomies/HierarchicalTaxon.svc" AllowMultipleSelection="true"> </sitefinity:HierarchicalTaxonSelectorResultView> </SelectorResultView> </designers:FilterSelectorItem> <designers:FilterSelectorItem ID="FilterSelectorItem2" runat="server" Text="<%$Resources:Labels, ByTags %>" GroupLogicalOperator="AND" ItemLogicalOperator="OR" ConditionOperator="Contains" QueryDataName="Tags" QueryFieldName="Tags" QueryFieldType="System.Guid"> <SelectorResultView> <sitefinity:FlatTaxonSelectorResultView ID="FlatTaxonSelectorResultView1" runat="server" WebServiceUrl="~/Sitefinity/Services/Taxonomies/FlatTaxon.svc" AllowMultipleSelection="true"> </sitefinity:FlatTaxonSelectorResultView> </SelectorResultView> </designers:FilterSelectorItem> </Items> </designers:FilterSelector> </div> </li> <li style="display: none;"> <asp:RadioButton runat="server" Enabled="false" ID="contentSelect_AdvancedFilter" GroupName="ContentSelection" Text="<%$Resources:Labels, AdvancedSelection %>" /><asp:Literal ID="Literal1" runat="server" Text="<%$Resources:Labels, InProcessOfImplementation %>" /> </li> </ul></div>Hi Antoine,
You can modify the control as shown below ( only for categories)
<designers:FilterSelector ID="filterSelector" runat="server" AllowMultipleSelection="true" ItemsContainerTag="ul" ItemTag="li" ItemsContainerCssClass="sfCheckListBox sfExpandedPropertyDetails" DisabledTextCssClass="sfTooltip"> <Items> <designers:FilterSelectorItem ID="FilterSelectorItem1" runat="server" Text="<%$Resources:Labels, ByCategories %>" GroupLogicalOperator="AND" ItemLogicalOperator="OR" ConditionOperator="Contains" QueryDataName="Categories" QueryFieldName="Category" QueryFieldType="System.Guid"> <SelectorResultView> <sitefinity:HierarchicalTaxonSelectorResultView ID="HierarchicalTaxonSelectorResultView1" runat="server" WebServiceUrl="~/Sitefinity/Services/Taxonomies/HierarchicalTaxon.svc" AllowMultipleSelection="true"> </sitefinity:HierarchicalTaxonSelectorResultView> </SelectorResultView> </designers:FilterSelectorItem> </Items></designers:FilterSelector>protected virtual FilterSelector filterSelector get return this.Container.GetControl<FilterSelector>("filterSelector", true); filterSelector.SetTaxonomyId("Categories", TaxonomyManager.CategoriesTaxonomyId);Thank you Ivan. I put the code you instructed me to add in my ControlDesignerBase subclass and everything is working.
In a related issue, I am trying to get the FlatTaxonField control working.
Eventually I would like to set it up with a new flat classification that I created, but for now, I am just trying to get it to work with the out-of-the-box Tags classification.
In my custom designer .aspx, I have the following:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="TabbedDocumentCollectionDesignerTemplate.ascx.cs" Inherits="SitefinityWebApp.Widgets.TabbedDocumentCollection.TabbedDocumentCollectionDesignerTemplate" %><%@ Register Assembly="Telerik.Sitefinity" TagPrefix="sitefinity" Namespace="Telerik.Sitefinity.Web.UI" %><%@ Register Assembly="Telerik.Sitefinity" TagPrefix="designers" Namespace="Telerik.Sitefinity.Web.UI.ControlDesign" %><%@ Register Assembly="Telerik.Sitefinity" TagPrefix="sfFields" Namespace="Telerik.Sitefinity.Web.UI.Fields" %><sfFields:FormManager ID="formManager" runat="server" /><div class="sfContentViews sfSingleContentView"> <div class="sfTxtFieldCtrl"> <sfFields:FlatTaxonField ID="fieldDocumentCollection" DisplayMode="Read" BindOnServer="true" runat="server" WebServiceUrl="~/Sitefinity/Services/Taxonomies/FlatTaxon.svc" Expanded="true" TaxonomyMetafieldName="DocumentCollectionsForDisplay" Title="Document Collections" HideWhenNoTaxaFound="false" CssClass="sfpostTagsWrp" /> </div></div>Type.registerNamespace("SitefinityWebApp.Widgets.TabbedDocumentCollection");SitefinityWebApp.Widgets.TabbedDocumentCollection.TabbedDocumentCollectionDesigner = function (element) SitefinityWebApp.Widgets.TabbedDocumentCollection.TabbedDocumentCollectionDesigner.initializeBase(this, [element]);SitefinityWebApp.Widgets.TabbedDocumentCollection.TabbedDocumentCollectionDesigner.prototype = initialize: function () SitefinityWebApp.Widgets.TabbedDocumentCollection.TabbedDocumentCollectionDesigner.callBaseMethod(this, 'initialize'); , dispose: function () SitefinityWebApp.Widgets.TabbedDocumentCollection.TabbedDocumentCollectionDesigner.callBaseMethod(this, 'dispose'); , refreshUI: function () var data = this._propertyEditor.get_control(); jQuery("#fieldDocumentCollection").val(data.DocumentCollectionsForDisplay); , applyChanges: function () var controlData = this._propertyEditor.get_control(); controlData.DocumentCollectionsForDisplay = jQuery("#fieldDocumentCollection").val(); SitefinityWebApp.Widgets.TabbedDocumentCollection.TabbedDocumentCollectionDesigner.registerClass('SitefinityWebApp.Widgets.TabbedDocumentCollection.TabbedDocumentCollectionDesigner', Telerik.Sitefinity.Web.UI.ControlDesign.ControlDesignerBase);if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();protected override void InitializeControls(Telerik.Sitefinity.Web.UI.GenericContainer container) base.DesignerMode = ControlDesignerModes.Simple; TaxonomyManager taxonomyManager = TaxonomyManager.GetManager(); FlatTaxonomy taxonomyDocumentCollection = taxonomyManager.GetTaxonomies<FlatTaxonomy>().Where(t => t.Name == "Tags").SingleOrDefault(); this.DocumentCollectionsField.TaxonomyId = taxonomyDocumentCollection.Id;protected virtual FlatTaxonField DocumentCollectionsField get return this.Container.GetControl<FlatTaxonField>("fieldDocumentCollection", true); Hi Antoine,
You need to supply TaxonomyId . Currently the control calls GetTaxonomy but you do not pass any value there, so it should be bound properly.
Greetings,
Ivan Dimitrov
the Telerik team
Hello Ivan
I am setting the TaxonomyId in InitializeControls of my ControlDesignerBase:
TaxonomyManager taxonomyManager = TaxonomyManager.GetManager();FlatTaxonomy taxonomyDocumentCollection = taxonomyManager.GetTaxonomies<FlatTaxonomy>() .Where(t => t.Name == "Tags") .SingleOrDefault();this.DocumentCollectionsField.TaxonomyId = taxonomyDocumentCollection.Id;Hello Antoine,
This looks fine. Do you get the control populated with data? In most of the places we set the property in the template directly.
Greetings,
Ivan Dimitrov
the Telerik team
Hello guys,
I don't find the answer for the original question : "How do I save the option values for the widget instance? Do I define a ContentSelection property and Category property for the widget?".
I'm able to display and select taxonomies (Tags/Categories) but in the javascript of my Desginer :
- I need to retrieve the tags/categories selected in the FilterSelector (applyChanges function) but I don't know how
- I need to set FilterSelector with the tags/categories that were selected before (refreshUI function).
Can somenone help me with this?
Thanks a lot for your help.
Jonathan.
Hi Jonathan
For various reasons, I dropped this task and thus never got it working. If you are able to, I would be glad to see your solution in this forum post.
Thanks,
Antoine
I have the same issues... I can't figure out how to get to pass the values back and forth between my control and the designer using applyChanges and refreshUI...
Hi All,
I opened a ticket about this issue and here's the answer I got from the support.
Hi Jonathan,
Thank you for the patience.I have explored several options for achieving this functionality, please find below my recommendations:
1. I'd recommend you to switch the implementation from FilterSelector to ChoiceField - you can customize the frontend representation by specifying myControl.RenderChoicesAs = Telerik.Sitefinity.Web.UI.Fields.Enums.RenderChoicesAs.(specify desired view)
An example of CHoice field implementation in a control designer can be found in the latest release of our SDK in the TaxonomyDropDown of the Products Catalog module.
You can define the ChoiceField in your template as:
<%@ Control Language="C#" %><%@ Register Assembly="Telerik.Sitefinity" TagPrefix="sitefinity" Namespace="Telerik.Sitefinity.Web.UI" %><%@ Register Assembly="Telerik.Web.UI, Version=2011.1.413.40" Namespace="Telerik.Web.UI" TagPrefix="telerik" %><%@ Register Assembly="Telerik.Sitefinity, Version=4.1.1395.0" Namespace="Telerik.Sitefinity.Web.UI.Fields" TagPrefix="sfFields" %> <ul class="sfRadioList sfTitledList"> <li> <sfFields:ChoiceField ID="hidePrice" runat="server" CssClass="sfInlineWrapper" DataFieldName="HidePriceOnFrontend" DisplayMode="Write" RenderChoicesAs="SingleCheckBox"> </sfFields:ChoiceField> </li></ul>protected override void InitializeControls(GenericContainer container) var tManager = TaxonomyManager.GetManager(); // var tid = tdefinition.TaxonomyId; var allTags = tManager.GetTaxa<FlatTaxon>(); //.GetTaxonomies<FlatTaxonomy>(); if (allTags != null) var myControl = this.Container.GetControl<ChoiceField>("hidePrice", true); myControl.RenderChoicesAs = Telerik.Sitefinity.Web.UI.Fields.Enums.RenderChoicesAs.CheckBoxes; // // or you can use Telerik.Sitefinity.Web.UI.Fields.Enums.RenderChoicesAs.CheckBoxes for multiple choice myControl.Choices.Clear(); foreach (var taxon in allTags) var choice = new ChoiceItem(); choice.Value = taxon.Id.ToString(); choice.Text = taxon.Title; choice.Enabled = true; myControl.Choices.Add(choice); public override IEnumerable<ScriptDescriptor> GetScriptDescriptors() var descriptor = new ScriptControlDescriptor(typeof(DatePickerDesignerView).FullName, this.ClientID); descriptor.AddComponentProperty("minimumPicker", this.MinimumPicker.ClientID); descriptor.AddComponentProperty("maximumPicker", this.MaximumPicker.ClientID); descriptor.AddComponentProperty("hidePrice", this.Container.GetControl<ChoiceField>("hidePrice", true).ClientID); return new[] descriptor ; public Guid[] MyTagSelection get if(this.myTagSelection == null) this.myTagSelection = new Guid[]; return this.myTagSelection; set this.myTagSelection = value; private Guid[] myTagSelection;refreshUI: function () debugger; var controlData = this.get_controlData(); var myTagSel = controlData.MyTagSelection; this.set_hidePrice(myTagSel); , // implementation of IDesignerViewControl: forces the designer view to apply the changes on UI to the control Data applyChanges: function () var controlData = this.get_controlData(); debugger; var tagSelection = this._hidePrice.get_value(); controlData.MyTagSelection = tagSelection; ,I've gotten the FilterSelector to work for categories successfully in a control designer(thanks to a little help from inspecting the Sitefinity libraries with JustDecompile). Start out as Ivan specified in his first post above. In the control designer CS file you will also need to register the ScriptDescriptor for the filter selector:
public override IEnumerable<ScriptDescriptor> GetScriptDescriptors() var baseDescriptors = new List<ScriptDescriptor>(base.GetScriptDescriptors()); var newDescriptors = (ScriptControlDescriptor)baseDescriptors.Last(); newDescriptors.AddComponentProperty("filterSelector", this.filterSelector.ClientID); return baseDescriptors;get_filterSelector: function () return this._filterSelector;,set_filterSelector: function (value) this._filterSelector = value;,refreshUI: function () var controlData = this.get_controlData(); var additionalFilters = this.get_controlData().CategoryJSON; if (additionalFilters) additionalFilters = Sys.Serialization.JavaScriptSerializer.deserialize(additionalFilters); this.get_filterSelector().set_queryData(additionalFilters);,applyChanges: function () var controlData = this.get_controlData(); var filterSelector = this.get_filterSelector(); filterSelector.applyChanges(); var queryData = filterSelector.get_queryData(); if (queryData.QueryItems && queryData.QueryItems.length > 0) queryData = Telerik.Sitefinity.JSON.stringify(queryData); else queryData = null; controlData.CategoryJSON = queryData;,// Technically, this variable would hold any of the filter data returned from the FilterSelector,// but it is only configured for Categories, so I'm naming the variable as suchpublic string CategoryJSON get; set; protected List<Guid> Categories get List<Guid> categoryGUIDList = new List<Guid>(); if (!string.IsNullOrEmpty(CategoryJSON)) //Parse the JSON string and extract the category IDs QueryData qData = (new JavaScriptSerializer()).Deserialize<QueryData>(CategoryJSON); List<QueryItem> categoryNames = qData.QueryItems.Where(qi => qi.Condition != null && qi.Condition.FieldName == "Category").ToList<QueryItem>(); foreach (QueryItem qi in categoryNames) categoryGUIDList.Add(Guid.Parse(qi.Value)); return categoryGUIDList; using Telerik.Sitefinity.Web.Model;using System.Web.Script.Serialization;Hi,
Thank you, Alan for sharing your solution.
Regards,
Stefani Tacheva
Telerik