Example - Developing a widget

The following scenario will guide you through the process of developing a simple page builder widget step-by-step with full code samples. For more detailed information about the underlying development principles, see our general pages about developing widgets, widget properties and inline editors.

Prerequisite

To be able to use the widget in the page builder, you need to enable the page builder feature and set up an editable area.

When finished, the widget displays a simple message with a number of your choice. The number is set via a widget property and can be modified through an inline property editor or the properties dialog. The widget can be added to an editable area and displayed on the live site.

Note: The following example is based on the LearningKit project. To use the code samples in your project, you need to modify the namespaces, identifiers and other occurrences where LearningKit is mentioned to match your project’s name.

Widget

Create a widget with one modifiable integer property.

Property model

Create a property model NumberWidgetProperties.cs in the ~/Models/Widgets/NumberWidget folder:




using Kentico.Forms.Web.Mvc;
using Kentico.PageBuilder.Web.Mvc;

namespace LearningKit.Models.Widgets.NumberWidget
{
    public class NumberWidgetProperties : IWidgetProperties
    {
        // Defines a property and sets its default value
        // Assigns the default Xperience text input component, which allows users to enter 
        // a numeric value for the property in the widget's configuration dialog
        [EditingComponent(IntInputComponent.IDENTIFIER, Order = 0, Label = "Number")]
        public int Number { get; set; } = 22;
    }
}


Partial view

Create a partial view _NumberWidget.cshtml in the ~/Views/Shared/Widgets folder:




@using Kentico.PageBuilder.Web.Mvc
@using Kentico.Web.Mvc

@using LearningKit.Models.InlineEditors.NumberEditor
@using LearningKit.Models.Widgets.NumberWidget

@model ComponentViewModel<NumberWidgetProperties>

<h3 style="background-color: #dddddd;">The number you chose for today is: @Model.Properties.Number</h3>

@* Shows an inline editor when rendered in the edit mode of the Pages application in Xperience *@
@if (Context.Kentico().PageBuilder().EditMode)
{
    Html.RenderPartial("InlineEditors/_NumberEditor", new NumberEditorModel
    {
        @* Use the nameof() operator to get the name of the edited property from the widget property model *@
        PropertyName = nameof(NumberWidgetProperties.Number),
        Number = Model.Properties.Number
    });
}


Widget registration

Register the widget into the system using the RegisterWidget assembly attribute. We recommend adding a dedicated code file to your project’s ~/App_Start folder for the purposes of component registration, for example named PageBuilderComponentRegister.cs.




using LearningKit.Models.Widgets.NumberWidget;

using Kentico.PageBuilder.Web.Mvc;

// Registers the 'Selected number' widget (it uses the system's default controller and ComponentViewModel)
[assembly: RegisterWidget("LearningKit.Widgets.NumberWidget", 
                          "Selected number", 
                          typeof(NumberWidgetProperties),
                          customViewName: "Widgets/_NumberWidget",
                          IconClass = "icon-octothorpe")]


Inline editor

Implement an inline editor able to modify the Number integer property.

Model

Create an editor model NumberEditorModel.cs in the ~/Models/InlineEditors/NumberEditor folder:




namespace LearningKit.Models.InlineEditors.NumberEditor
{
    public class NumberEditorModel
    {
        public string PropertyName { get; set; }

        public int Number { get; set; }
    }
}


Partial view

Create a partial view _NumberEditor.cshtml in the ~/Views/Shared/InlineEditors folder:




@using Kentico.PageBuilder.Web.Mvc
@using Kentico.Web.Mvc

@model LearningKit.Models.InlineEditors.NumberEditor.NumberEditorModel

@using (Html.Kentico().BeginInlineEditor("number-editor", Model.PropertyName))
{
    <div style="position: absolute; top: 0px; right: 0px;">
        <button id="plus-btn" type="button">+</button>
        <button id="minus-btn" type="button">-</button>
    </div>
}


JavaScript

Create a JavaScript file number-editor.js in the ~/Content/InlineEditors/NumberEditor folder:




(function () {
    // Registers the 'number-editor' inline property editor within the page builder scripts
    window.kentico.pageBuilder.registerInlineEditor("number-editor", {
        init: function (options) {
            var editor = options.editor;

            // Click action for the 'Plus' button
            editor.querySelector("#plus-btn").addEventListener("click", function () {
                // Creates a custom event that notifies the widget about a change in the value of a property
                var event = new CustomEvent("updateProperty", {
                    detail: {
                        value: options.propertyValue + 1,
                        name: options.propertyName
                    }
                });
                editor.dispatchEvent(event);
            });

            // Click action for the 'Minus' button
            editor.querySelector("#minus-btn").addEventListener("click", function () {
                var event = new CustomEvent("updateProperty", {
                    detail: {
                        value: options.propertyValue - 1,
                        name: options.propertyName
                    }
                });
                editor.dispatchEvent(event);
            });
        }
    });
})();


The location of the script file under ~/Content/InlineEditors ensures that the script is automatically linked in the administration interface on pages containing editable areas (within a bundle of inline editor scripts).

Note: The following example is based on the LearningKit project. To use the code samples in your project, you need to modify the namespaces, identifiers and other occurrences where LearningKit is mentioned to match your project’s name.

Widget

Create a widget with one modifiable integer property.

Property model

Create a property model NumberWidgetProperties.cs in the ~/Component/Widgets/NumberWidget folder:




using Kentico.Forms.Web.Mvc;
using Kentico.PageBuilder.Web.Mvc;

namespace LearningKitCore.Components.PageBuilder.Widgets.NumberWidget
{
    public class NumberWidgetProperties : IWidgetProperties
    {
        // Defines a property and sets its default value
        // Assigns the default Xperience text input component, which allows users to enter
        // a numeric value for the property in the widget's configuration dialog
        [EditingComponent(IntInputComponent.IDENTIFIER, Order = 0, Label = "Number")]
        public int Number { get; set; } = 22;
    }
}


Partial view

Create a partial view _NumberWidget.cshtml in the ~/Components/Widgets/NumberWidget folder:




@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@using Kentico.PageBuilder.Web.Mvc

@using LearningKitCore.Components.PageBuilder.InlineEditors.NumberEditor
@using LearningKitCore.Components.PageBuilder.Widgets.NumberWidget

@inject IPageBuilderDataContextRetriever pageBuilderContext

@model ComponentViewModel<NumberWidgetProperties>

<h3 style="background-color: #dddddd;">The number you chose for today is: @Model.Properties.Number</h3>

@* Shows an inline editor when rendered in the edit mode of the Pages application in Xperience *@
@if (pageBuilderContext.Retrieve().EditMode)
{
    var inlineEditorModel = new NumberEditorModel
    {
        @* Use the nameof() operator to get the name of the edited property from the widget property model *@
        PropertyName = nameof(NumberWidgetProperties.Number),
        Number = @Model.Properties.Number
    };

    <partial name="~/Components/PageBuilder/InlineEditors/NumberEditor/_NumberEditor.cshtml" model="inlineEditorModel" />
}


Widget registration

Register the widget into the system using the RegisterWidget assembly attribute.




[assembly: RegisterWidget("LearningKit.Widgets.NumberWidget",
                         "Number selector",
                         typeof(NumberWidgetProperties),
                         customViewName: "~/Components/PageBuilder/Widgets/NumberWidget/_NumberWidget.cshtml")]



Inline editor

Implement an inline editor able to modify the Number integer property.

Model

Create an editor model NumberEditorModel.cs in the ~/Components/InlineEditors/NumberEditor folder:




namespace LearningKitCore.Components.PageBuilder.InlineEditors.NumberEditor
{
    public class NumberEditorModel
    {
        public string PropertyName { get; set; }

        public int Number { get; set; }
    }
}


Partial view

Create a partial view _NumberEditor.cshtml in the ~/Components/InlineEditors/NumberEditor folder:




@using Kentico.PageBuilder.Web.Mvc
@using Kentico.Web.Mvc

@model LearningKitCore.Components.PageBuilder.InlineEditors.NumberEditor.NumberEditorModel

@using (Html.Kentico().BeginInlineEditor("number-editor", Model.PropertyName))
{
    <div style="position: absolute; top: 0px; right: 0px;">
        <button id="plus-btn" type="button">+</button>
        <button id="minus-btn" type="button">-</button>
    </div>
}


JavaScript

Create a JavaScript file number-editor.js in the ~/wwwroot/PageBuilder/Admin/InlineEditors/NumberEditor folder (this example assumes the default configuration of the system’s bundling support, see Bundling static assets of builder components):




(function () {
    // Registers the 'number-editor' inline property editor within the page builder scripts
    window.kentico.pageBuilder.registerInlineEditor("number-editor", {
        init: function (options) {
            var editor = options.editor;

            // Click action for the 'Plus' button
            editor.querySelector("#plus-btn").addEventListener("click", function () {
                // Creates a custom event that notifies the widget about a change in the value of a property
                var event = new CustomEvent("updateProperty", {
                    detail: {
                        value: options.propertyValue + 1,
                        name: options.propertyName
                    }
                });
                editor.dispatchEvent(event);
            });

            // Click action for the 'Minus' button
            editor.querySelector("#minus-btn").addEventListener("click", function () {
                var event = new CustomEvent("updateProperty", {
                    detail: {
                        value: options.propertyValue - 1,
                        name: options.propertyName
                    }
                });
                editor.dispatchEvent(event);
            });
        }
    });
})();


Dancing Goat sample site

If you implement this example on the Dancing Goat sample site, you need to manually trigger the bundling process to include component scripts in the administration interface. You need to do the following:

  1. Run the pageBuilder Grunt task available in the sample site to manually trigger the bundling process.
  2. Clear cached web content in your browser.

The location of the script file under ~/wwwroot/PageBuilder/Admin/InlineEditors/NumberEditor ensures that the script is automatically linked in the administration interface on pages containing editable areas (within a bundle of inline editor scripts).