Use content item selectors

When working with MVC widgets and widget designers, you may need to implement selectors for single or multiple items. The following article explains the basic principles of using such item selectors for various items, such as dynamic items, News items, taxa from a flat taxonomy. Selectors use standard Sitefinity CMS services to get the corresponding items. For example, the NewsService is used to get all created News items. Selectors also set the selected items into the designer properties.

The following example demonstrates how to use the News selector and is divided in two sections - selecting a single News item and selecting multiple News items. 

PREREQUISITES:

You created a widget with a custom designer view and an AngularJS controller for the widget. For more information, see Create widgets.

Use selectors

Selectors are part of the Telerik.Sitefinity.Frontend assembly. Selectors are implemented as AngularJS directives. To use selectors, you need to:

  1. Declare a module dependency in the widget designer controller
  2. Add the selector in the designer view

Common setup

  1. In the MVC/Controllers folder, create the CustomWidgetController.cs widget controller.
  2. In the MVC/Views/CustomWidget folder, create the custom designer view DesignerView.SimpleSelector.cshtml for your widget.
  3. In the MVC/Scripts/CustomWidget folder, create the AngularJS controller designerview-simpleselector.js for the custom designer view.

Single News item selector

The controller must have two properties:

  • SerializedSelectedItemId
  • SerializedSelectedItem

The following code demonstrates how to implement the CustomWidgetController_SingleSelector.cs controller:

using System.Web.Mvc;
using Telerik.Sitefinity.Mvc;
[ControllerToolboxItem(Name = "CustomWidget", Title = "My Custom MVC widget", SectionName = "Custom MVC Widgets")]
public class CustomWidgetController : Controller
{
public string SerializedSelectedItemId { get; set; }
public string SerializedSelectedItem { get; set; }
public ActionResult Index()
{
return this.View();
}
}

Next, you implement the custom designer view:

<sf-list-selector sf-news-selector
sf-selected-item-id="newsSelector.selectedItemId"
sf-selected-item="newsSelector.selectedItem">
</sf-list-selector>

Finally, implement he AngularJS controller:

(function () {
// declare dependency on the sfSelectors module
angular.module('designer').requires.push('sfSelectors');
angular.module('designer').controller('SimpleSelectorCtrl', ['$scope', 'propertyService', function ($scope, propertyService) {
$scope.feedback.showLoadingIndicator = true;
// initialize the news selector model
$scope.newsSelector = {
selectedItemId: [],
selectedItem: []
};
// whenever newsSelector.selectedItemId changes, bind the new value to the widget controller property
$scope.$watch(
'newsSelector.selectedItemId',
function (newSelectedItemId, oldSelectedItemId) {
if (newSelectedItemId !== oldSelectedItemId) {
if (newSelectedItemId) {
$scope.properties.SerializedSelectedItemId.PropertyValue = newSelectedItemId;
}
}
},
true
);
// whenever newsSelector.selectedItem changes, bind the new value to the widget controller property
$scope.$watch(
'newsSelector.selectedItem',
function (newSelectedItem, oldSelectedItem) {
if (newSelectedItem !== oldSelectedItem) {
if (newSelectedItem) {
$scope.properties.SerializedSelectedItem.PropertyValue = JSON.stringify(newSelectedItem);
}
}
},
true
);
propertyService.get()
.then(function (data) {
if (data) {
$scope.properties = propertyService.toAssociativeArray(data.Items);
// copy the selected item id so that the selector can initialize with the selected items
var selectedItemId = $scope.properties.SerializedSelectedItemId.PropertyValue || null;
if (selectedItemId) {
$scope.newsSelector.selectedItemId = selectedItemId;
}
}
},
function (data) {
$scope.feedback.showError = true;
if (data)
$scope.feedback.errorMessage = data.Detail;
})
.finally(function () {
$scope.feedback.showLoadingIndicator = false;
});
}]);
})();

Multiple News items selector

The controller must have two properties:

  • SerializedSelectedItemsId
  • SerializedSelectedItems

NOTE: The controller properties are not the same as the ones for the single item selector since they are in plural.

The following code demonstrates how to implement the CustomWidgetController_MultipleSelector.cs controller:

using System.Web.Mvc;
using Telerik.Sitefinity.Mvc;
[ControllerToolboxItem(Name = "CustomWidget", Title = "My Custom MVC widget", SectionName = "Custom MVC Widgets")]
public class CustomWidgetController_MultipleSelector: Controller
{
public string SerializedSelectedItemsIds { get; set; }
public string SerializedSelectedItems { get; set; }
public ActionResult Index()
{
return this.View();
}
}

Next, you implement the custom designer view:

<sf-list-selector sf-news-selector
sf-multiselect="true"
sf-selected-ids="newsSelector.selectedItemsIds"
sf-selected-items="newsSelector.selectedItems">
</sf-list-selector>

In the code above, to enable selection of multiple items for the selector, you set the sf-multiselect attribute true. Take notice that the attributes that bind the collections of items and item IDs are also different than the ones for a single item selector: sf-selected-ids and sf-selected-items. The selector model properties need to correspond to the ones you defined in the widget designer controller.

Finally, implement he AngularJS controller:

(function () {
angular.module('designer').requires.push('sfSelectors');
angular.module('designer').controller('SimpleSelectorCtrl', ['$scope', 'propertyService', function ($scope, propertyService) {
var emptyGuid = '00000000-0000-0000-0000-000000000000';
$scope.feedback.showLoadingIndicator = true;
$scope.newsSelector = {
selectedItemsIds: [],
selectedItems: []
};
$scope.$watch(
'newsSelector.selectedItemsIds',
function (newSelectedItemsIds, oldSelectedItemsIds) {
if (newSelectedItemsIds !== oldSelectedItemsIds) {
if (newSelectedItemsIds) {
$scope.properties.SerializedSelectedItemsIds.PropertyValue = JSON.stringify(newSelectedItemsIds);
}
}
},
true
);
$scope.$watch(
'newsSelector.selectedItems',
function (newSelectedItems, oldSelectedItems) {
if (newSelectedItems !== oldSelectedItems) {
if (newSelectedItems) {
$scope.properties.SerializedSelectedItems.PropertyValue = JSON.stringify(newSelectedItems);
}
}
},
true
);
propertyService.get()
.then(function (data) {
if (data) {
$scope.properties = propertyService.toAssociativeArray(data.Items);
var selectedItemsIds = $.parseJSON($scope.properties.SerializedSelectedItemsIds.PropertyValue || null);
if (selectedItemsIds) {
$scope.newsSelector.selectedItemsIds = selectedItemsIds;
}
}
},
function (data) {
$scope.feedback.showError = true;
if (data)
$scope.feedback.errorMessage = data.Detail;
})
.finally(function () {
$scope.feedback.showLoadingIndicator = false;
});
}]);
})();

Want to learn more?

Increase your Sitefinity skills by signing up for our free trainings. Get Sitefinity-certified at Progress Education Community to boost your credentials.

Get started with Integration Hub | Sitefinity Cloud | Sitefinity SaaS

This free lesson teaches administrators, marketers, and other business professionals how to use the Integration hub service to create automated workflows between Sitefinity and other business systems.

Web Security for Sitefinity Administrators

This free lesson teaches administrators the basics about protecting yor Sitefinity instance and its sites from external threats. Configure HTTPS, SSL, allow lists for trusted sites, and cookie security, among others.

Foundations of Sitefinity ASP.NET Core Development

The free on-demand video course teaches developers how to use Sitefinity .NET Core and leverage its decoupled architecture and new way of coding against the platform.

Was this article helpful?