Developing modal dialogs for builder component properties
Modal dialogs are an alternative way of editing the properties of form or page builder components in the administration interface (not on the live site). When configuring a builder component, modal dialogs allow you to display an additional pop-up window, where the content editor can adjust the component’s properties.
The system supports modal dialogs in the following locations:
- Within the page builder interface of the Pages application:
Through an inline editor of a widget property.
In the property configuration dialog of the following components (using a custom form component):
- Within the form builder interface of the Forms application:
- In the properties panel of form fields (using a custom form component).
Modal dialogs are suitable for advanced property editors with potentially large dimensions. Such editors would otherwise seize a great part of the configuration dialog or cover the content of widgets if implemented as inline editors. Typical examples of modal dialogs are selectors or complex editors with multiple required inputs.
The system provides a JavaScript API that helps developers open modal dialogs and integrate them into the administration interface. Developers have unlimited freedom with regards to the implementation of the modal dialog window itself.
On this page, you can find instructions and best practices for the development of modal dialogs. To implement a modal dialog, you need to:
- Develop MVC elements that define the markup of the dialog window. See Creating dialog markup.
- Prepare inline editors or form components for the properties where you want to use the dialog.
- Add scripts that open the modal dialog to the given inline editors or form components. See Opening dialogs.
You can find a Basic example of a modal dialog implementation below.
Using page builder data selectors
By default, the system contains form components and JavaScript API support to select data from the content tree (pages) and media libraries (media files), which can be used in the page builder interface.
Creating dialog markup
Create Model/View/Controller elements that represent the modal dialog according to the MVC best practices.
- Model
- Store the model in the ~/Models/ModalDialogs folder.
- View
- Store the modal dialog view in the ~/Views/Shared/ModalDialogs/<DialogName>folder.
- The view must define a full HTML page, including html, head and body tags. This is required because the model dialog is loaded as a separate HTML document in an iframe.
- The view must contain a link to modal dialog scripts. Use the @Html.Kentico().ModalDialogScript() extension method (available in the Kentico.Components.Web.Mvc.Dialogs namespace) in the head section of the markup.
- The view must contain links to all necessary resources, such as related stylesheets and scripts.
- Within scripts in the view, you can use the following functions available in the kentico.modalDialog namespace:
- open(modalDialogOptions) – opens a new modal dialog. See below.
- close() – closes the modal dialog without applying the changes.
- apply() – applies the changes and closes the modal dialog.
- getData() – returns the data object provided when the dialog was opened using the kentico.modalDialog.open function. See the data property of the modal dialog options object below.
- contentSelector.open(contentSelectorOptions) – enables you to open the content selector dialog. For more information, visit the content selector JavaScript API documentation.
- Controller
- Store the modal dialog controller in the ~/Controllers/ModalDialogs folder.
Opening dialogs
To open a modal dialog, use the kentico.modalDialog.open function in an inline editor script or as part of a form component script. Provide an options object with the following properties as a parameter of the function:
Required properties | |
Property | Description |
url | The URL of the model dialog content. Typically, use the URL matching the route of the controller action that displays the modal dialog’s view. The route URL must be generated and resolved on the server and you need to ensure that it is propagated to the client script. For example, you can use one of the following approaches:
Editing component markup
Note: If you need to access any content requiring authentication (e.g. the current user), you need to additionally use the AuthenticateUrl extension method (available in the Kentico.Content.Web.Mvc namespace) to add an appropriate authentication hash to the URL. |
applyCallback | A callback function invoked when the dialog’s confirmation button is clicked. Within this function, you need to ensure retrieving of the value selected in the dialog and propagation of the value to the component which opened the dialog. To propagate the value from the modal dialog to the component which invoked the modal dialog:
|
Optional properties | |
Property | Description |
applyButtonText | A string property allowing you to set a custom label for the dialog confirmation button. |
cancelButtonText | A string property allowing you to set a custom label for the dialog cancel button. |
cancelCallback | A callback function invoked when the dialog is closed. Similar to applyCallback(see above). |
data | An object which can be used to pass data of any type to the dialog (like a model in MVC architecture). This object can be retrieved in a script within a dialog using the kentico.modalDialog.getData function. |
maximized | A boolean value which indicates whether the dialog is displayed in maximized size. If set to true, it overrides the width property. |
showFooter | A boolean value which indicates whether the footer of the dialog is shown. |
theme | A string value that sets the header color for the dialog, so that it matches the interface element from which the dialog was opened. Choose one of the following available themes:
The default dialog theme is widget (blue). If a modal dialog is opened from a configuration dialog (via a form component), the theme inherits from the given configuration dialog. |
title | A string property whose value is displayed in the header when the dialog is opened in the user interface. |
width | CSS width property of the modal dialog. For example “250px” or “80%”. This property can be affected by the maximized property. |
Example – Developing a simple modal dialog
The following example leads you through the process of developing a modal dialog that allows users to select the background color of a widget. This dialog can be opened either through an inline editor, or through a button in the configuration dialog of a widget.
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.
Prerequisites
You need to implement the following components to be able to utilize the modal dialog:
- A widget with a property that determines its background color.
- An inline editor containing a button that opens the modal dialog.
– OR –
A form component containing a text input field and a button that opens the modal dialog.
Modal dialog view model
Create a ColorModalDialogViewModel.cs file in the ~/Models/ModalDialogs folder:
using System.Collections.Generic;
namespace LearningKit.Models.ModalDialogs
{
public class ColorModalDialogViewModel
{
public IEnumerable<string> Colors { get; set; }
}
}
Modal dialog view
Create a _ColorModalDialog.cshtml file in the ~/Views/Shared/ModalDialogs/ColorModalDialog folder:
@using Kentico.Components.Web.Mvc.Dialogs
@model LearningKit.Models.ModalDialogs.ColorModalDialogViewModel
<!DOCTYPE html>
<html>
<head>
@Html.Kentico().ModalDialogScript()
<meta name="viewport" content="width=device-width" />
</head>
<body>
<form action="">
@foreach (var color in Model.Colors)
{
<input type="radio" id="@color" name="color" value="@color" />
<label for="@color">@color</label><br />
}
</form>
@* Script that preselects the radio button of the current color
Gets the value from the data passed when the 'kentico.modalDialog.open' function is called *@
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function () {
var defaultValue = kentico.modalDialog.getData().value;
document.getElementById(defaultValue).checked = true;
});
</script>
</body>
</html>
Modal dialog controller
Create a ColorModalDialogController.cs file in the ~/Controllers/ModalDialogs folder:
using System.Collections.Generic;
using System.Web.Mvc;
using LearningKit.Models.ModalDialogs;
namespace LearningKit.Controllers.ModalDialogs
{
public class ColorModalDialogController : Controller
{
public ActionResult Index()
{
var model = new ColorModalDialogViewModel
{
Colors = new List<string>() { "red", "blue", "white", "green", "black", "gray", "yellow" }
};
return View("ModalDialogs/ColorModalDialog/_ColorModalDialog", model);
}
}
}
Opening the modal dialog
Use one of the following approaches.
Form component
In the view of the form component, generate the modal dialog URL and pass it to the client function that opens the model dialog:
@using Kentico.Forms.Web.Mvc
@model LearningKit.FormBuilder.FormComponents.ColorFormComponent
@{
// Gets a collection of system HTML attributes necessary for the functionality of form component inputs
IDictionary<string, object> htmlAttributes = ViewData.Kentico().GetEditorHtmlAttributes();
// Prepares data that will be passed to the function that opens the modal dialog
string dialogData = Newtonsoft.Json.JsonConvert.SerializeObject(new
{
modalDialogUrl = Url.Action("Index", "ColorModalDialog"),
colorInputId = Html.IdFor(m => m.Value).ToHtmlString()
});
}
@* Textbox input element that displays/edits the form component's color value *@
@Html.TextBoxFor(m => m.Value, htmlAttributes)
@* Button that opens the modal dialog when clicked *@
<button type="button" class="ktc-btn ktc-btn-default" onclick="openColorModalDialog(@dialogData)">Open dialog</button>
Execute the following function when a button to open the modal dialog is clicked:
function openColorModalDialog(dialogData) {
// Gets the form component's input element
var inputElement = window.document.querySelector('#' + dialogData.colorInputId);
// Opens the modal dialog
kentico.modalDialog.open({
url: dialogData.modalDialogUrl,
applyCallback: function(dialogWindow) {
// Retrieves the selected value from the modal dialog
var selectedValue = dialogWindow.document.querySelector('input[name="color"]:checked').value;
// Updates the value of the input element in the property configuration dialog
inputElement.value = selectedValue;
},
applyButtonText: 'Confirm color selection',
title: 'Select a color',
// Passes the current color to the modal dialog data
data: { value: inputElement.value }
});
}
Inline editor
In the view of the inline editor, generate the modal dialog URL and pass it as an HTML attribute argument of the BeginInlineEditor function (which generates the inline editor wrapping element).
@using Kentico.PageBuilder.Web.Mvc
@using Kentico.Web.Mvc
@model LearningKit.Models.InlineEditors.ColorEditor.ColorEditorModel
@using (Html.Kentico().BeginInlineEditor("color-editor",
Model.PropertyName,
new { data_url = Url.Action("Index", "ColorModalDialog") }))
{
<div style="position: absolute; top: 0px; right: 20px;">
<button id="modal-btn" type="button">Change color</button>
</div>
}
Modify the init property of the registration function in the inline editor’s script:
init: function (options) {
var editor = options.editor;
// Adds a click action for the 'Modal dialog' button
editor.querySelector("#modal-btn").addEventListener("click", function () {
// Opens the modal dialog window
kentico.modalDialog.open({
// Gets the modal dialog URL from the 'data-url' attribute of the inline editor wrapping element
url: editor.getAttribute("data-url"),
applyCallback: function (dialogWindow) {
// Creates and dispatches an event that notifies the widget about changes of properties
var event = new CustomEvent("updateProperty", {
detail: {
// Retrieves the color value from radio buttons within the modal dialog window
value: dialogWindow.document.querySelector('input[name="color"]:checked').value,
name: options.propertyName
}
});
editor.dispatchEvent(event);
},
applyButtonText: "Confirm color selection",
title: "Select a color",
// Passes the current color value to the modal dialog data
data: { value: options.propertyValue }
});
});
}