Feather: Extend designers with client logic
With Feather, you can extend widget designers with additional client logic.
Feather uses a naming convention for resolving designer views and designer assets like scripts. For example, you are creating a designer view, named Custom. The following table summarizes Feather naming conventions.
Name of |
Convention |
Location of files |
Razor view |
Custom.cshtml |
~/MVC/Views/Custom |
Designer view |
DesignerView.Custom.cshtml |
~/MVC/Views/Custom |
JSON configuration |
DesignerView.Custom.json |
~/MVC/Views/Custom
|
Script |
designerview-custom.js |
~/MVC/Scripts/Custom
designerview-custom.js containing AngularJS controller named CustomCtrl
|
Angular controller |
CustomCtrl |
NOTE: In case you are implementing your custom widget designer in an external assembly, you need to mark all files as an EmbeddedResource, including custom script references inside the JSON configuration.
Each designer view can require a set of additional scripts to be rendered. You define this set in a JSON
file that has the same name as the view template. For example, if you want to add additional script reference to the designer's simple view of the Content block widget, you create a DesignerView.Simple.json
with the following content:
{
"priority"
: 1,
"scripts"
: [
"Mvc/Scripts/ContentBlock/shared-content-services.js"
,
"Mvc/Scripts/MyAdditionalScript.js"
]
}
In the code above:
- You override the
JSON
with the shared-content-services.js
, which is used by the default simple view of the Content block designer
- The
priority
property indicates that the respective view must be displayed by default, rather than other views with lower priority.
NOTE: If you create a new view and you want this view to be default, just set the view with highest priority.
NOTE: If in your designer view you use only client components, the JSON
file is generated automatically and you do not need to create it. If no other designer views with explicitly set priority exists, the priority of the designer view is set to 1. In case you need to have full control over the scripts that are loaded or you want to set custom priority, you will still need the JSON
file. If you have a JSON
file that matches the convention (even if empty), this automatic scripts registration will not occur.
For more information, see Feather: Client components.
Create designer controllers
After you create the new designer view, Feather automatically creates an AngularJs controller for this view. You can, however, add your own AngularJs controller if your scenario requires more complicated logic.
By default, if the script for your view is located either in the Mvc
folder of your Sitefinity CMS web application, or in a folder inside the assembly where the widget is implemented, the script is properly referenced.
NOTE: If the script file is in an assembly, make sure to add it inside the project files and set its build action to Embedded resource.
You must name your controller the same as the corresponding view but with Ctrl
suffix. You can define it through the following options:
- Directly in the designer module:
angular.module('designer').controller(...);
- In its own module and then add that module to the designer module's dependencies:
angular.module('designer').requires.push('myCustomModule');
Thus, Feather automatically associates the new controller with the view that you created.
NOTE: If in your designer view you use only client components, you do not need to create the .js
file – all angular dependencies will be added to the designer module. If you have a .js
file that matches the convention (even if empty), this automatic modules referencing will not occur.
The following example code demonstrates a sample controller for a view named Custom
:
var customModule = angular.module(
'customModule'
, [
'pageEditorServices'
,
'breadcrumb'
]);
angular.module(
'designer'
).requires.push(
'customModule'
);
//basic controller for the advanced designer view
customModule.controller(
'CustomCtrl'
, [
'$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
;
});
}]);
The controller code above demonstrates how you can populate the widget properties by invoking the property service. Thefeedback
property comes from $rootScope
and enables controllers to manipulate parts of the dialog's interface.