Ability to sort custom content type in designer
I have a custom widget that displays a list of custom content types (products). I want to give the ability for the user to set the display order in the widget designer. So for example i have product1, product2, product3, and product4. In the designer I would like a sortable list of the products and the user can ideally drag and and move the products around to set their order as desired. I see this functionality in various parts of Sitefinity (such as related data section of a content). How to do this in the widget designer?
Using Feather 9.1.
Update: I think I can accomplish this via the sf-list-selector. I have the tag below in the designer. However I am getting an exception in the log file when i press save in the designer:
End element 'PropertyValue' from namespace '' expected. Found element 'item' from namespace ''. I don't have a view JSON or JS file.
<
sf-list-selector
sf-dynamic-items-selector
sf-provider
=
"properties.ProductProviderName.PropertyValue"
sf-item-type
=
"properties.ProductType.PropertyValue"
sf-multiselect
=
"true"
sf-sortable
=
"true"
sf-master
=
"true"
sf-selected-ids
=
"properties.ProductIds.PropertyValue"
/>
See same issue reported here: www.sitefinity.com/.../multiple-content-item-selector-for-dynamic-items-in-widget-designer
Making a little progress. It turns out the value for the sf-selected-ids attribute needs to be in JSON array format. e.g. [ productId1, productId2, productId3]. Otherwise the backend service throws that exception. However, the selector by itself creates the string as product1, product2, product3. I.e. without the brackets.
So from what i gather, I need to create a JS file for designer that'll do that mapping back and forth. Will report back on progress.
OK, got it going finally. Here is the selector in the designer view (DesignerView.Simple.cshtml):
<
sf-list-selector
sf-dynamic-items-selector
sf-provider
=
"properties.ProductProviderName.PropertyValue"
sf-item-type
=
"properties.ProductType.PropertyValue"
sf-multiselect
=
"true"
sf-sortable
=
"true"
sf-master
=
"true"
sf-selected-ids
=
"productIds"
/>
As mentioned above, you'll need the designer JS file to do the JSON conversion back and forth. So I save this in the MVC/Scripts/[WidgetName]/designer-simple.json: (Simple is the name of the designer view)
(function ($)
var designerModule = angular.module('designer');
angular.module('designer').requires.push('sfSelectors');
designerModule.controller('SimpleCtrl', ['$scope', 'propertyService', function ($scope, propertyService)
$scope.feedback.showLoadingIndicator = true;
propertyService.get().then(function (data)
if (data)
$scope.properties = propertyService.toAssociativeArray(data.Items);
,
function (data)
$scope.feedback.showError = true;
if (data)
$scope.feedback.errorMessage = data.Detail;
).finally(function ()
$scope.feedback.showLoadingIndicator = false;
);
$scope.$watch('properties.ProductIds.PropertyValue', function (newValue, oldValue)
if (newValue)
$scope.productIds = JSON.parse(newValue);
);
$scope.$watch('productIds', function (newValue, oldValue)
if (newValue)
$scope.properties.ProductIds.PropertyValue = JSON.stringify(newValue);
);
]);
)(jQuery);
Lastly I added a DesignerView.Simple.json file in the same folder as DesignerView.Simple.cshtml:
"priority": 1,
"scripts": [
"client-components/selectors/common/sf-selected-items-view.js"
],
"components" : ["sf-dynamic-items-selector"]
Now the widget controller has a ProductIds property. It's values will be in format [productId1, productId2, etc.]. I used a JSON deserializer to get an array of products for the controller Index action:
public class ProductServicesWidgetController : Controller
private string productProviderName = WebConfigurationManager.AppSettings["productProviderName"];
private string productTypeName = WebConfigurationManager.AppSettings["productTypeName"];
public string ProductIds get; set;
public string ProductType
get return productTypeName;
set productTypeName = value;
public string ProductProviderName
get return productProviderName;
set productProviderName = value;
public ActionResult Index()
var selectedProducts = string.IsNullOrEmpty(this.ProductIds) ? new Guid[0] : JsonConvert.DeserializeObject<
Guid
[]>(this.ProductIds);
// ... rest of your controller index action