MVC Widgets: Structure and Best Practices
This article will provide a break down of the individual components of an MVC widget and provide best practices and items to look out for while developing these powerful components.
One of the largest advantages of using Kentico EMS as a platform has been the use of web parts and widgets to make building and customizing your site as easy as possible, but this feature wasn’t available in our MVC offering. This meant that for every little change to the design of the page or ordering of elements that a marketer or content administrator wanted to make, they would have to approach a developer to make the change. Enter MVC widgets–these widgets allow developers to create components for their MVC pages to allow their not-so-technical users to add, remove, or move elements around a given page.
Something that you may notice about MVC widgets is that there are only a few example widgets out-of-the-box. This is in order to give developers full control over the code for the editing, retrieval, caching, and display for the widgets. The goal of this article is to lay out the anatomy of these widgets and the key things to look out for while developing them.
The Widget Components:
One thing to remember about widgets is that there are two main pieces that the editor will see: the widget output and the inline editor for the widget which allows the user to customize and set properties. You will not need all of these components for every scenario; for example, if a developer wants to provide a widget that does not have any configuration they can skip all of the inline editor pieces.
When breaking down a widget into its MVC components, it boils down to a few core pieces:
- Widget ViewModel: This will store the actual data that will be used in the view for the widget
- Properties Model: This stores the data that the non-technical user is inputting in the Kentico UI
- Inline editor ViewModel: This ViewModel should contain at least two properties–the name and value of the widget property managed by the editor. It will be used as the ViewModel for the partial view of the editing control.
- Widget Controller: This handles the logic that will be used to populate the ViewModel for the widget using the properties from the property model. It will return a PartialView along with the ViewModel as its ActionResult. The RegisterWidget() assembly attribute added to this controller handles the registration of the widget into the system.
- Inline editor Controller (optional): This is not always necessary. However, if you need to do some additional processing to convert the value selected from the editing control before setting the property, you should do it here. An example of when this might be needed is in an image upload control–the image is selected via the browser, but you probably don’t want to put the binary data directly into the field. You can use the controller to upload the file and then a GUID or path could be stored in the field instead.
- Widget partial view: This is the view that will use the ViewModel passed to it by the controller to display the output of the widget. Inside this partial view, you will also need to add the condition to check if the page is being edited or viewed. If it is being displayed in the editing context, then we need to render another partial view that is our inline editor control.
- Inline editor partial view: This view is going to handle the display of the editing control for the field. This will be rendered from the partial view for the widget when the user is in the editing UI.
For an MVC developer, these concepts should be very familiar which will make creating these widgets a breeze and using them even easier. To get more in-depth details and code samples for creating a widget you can check out our documentation:
While developing widgets, there are a few things that developers should make sure to look out for; reviewing these items before you begin will save you a lot of time!
- The system automatically creates bundles containing all .js and .css files located under ~/Content/Widgets, ~/Content/Sections and ~/Content/InlineEditors. The bundles are then linked on all pages with page builder editable areas as one large bundle of resources. This means you can simply add “shared” resources in shared folders within these directories instead of adding it to each of the widgets that use the resource.
If your project is in debug mode, make sure your resources do not have “.min” in their naming as they will not be bundled since they are considered release resources, not debug. You can either simply remove the “.min” from the naming, or use the non-minified resource while in development.
Keep in mind that it is possible to add multiple instances of the same widget to the same page. When developing inline editors and using things like modal windows, you should make sure to take into account the unique identifier surrounding the widget. You will find the widget’s unique identifier in the div class labeled “ktc-widget” surrounding each widget on the page. It can be helpful in identifying which modal window to popup.
Apart from initialization code, avoid linking or executing scripts directly within widget views. This could lead to duplicated scripts on pages that contain multiple instances of the same widget as well.
If these initializations happen frequently and are deemed necessary, feel free to use a library like domready to make it a bit easier
Only use the ~/Content/Widgets directory to add basic styles that are required for the widget to render correctly. Any site-specific styles that finalize the live site design of the widget should be handled separately within the given site's main stylesheet.
To avoid potential conflicts between styles from other third-party components, we recommend adding a unique prefix to your CSS classes and identifiers (for example “#CompanyName-mid-button”), or employ similar measures to ensure their uniqueness.
Don’t make any assumptions about the relative order of the source CSS in the resulting bundles–individual stylesheet files contained in the bundle may or may not precede each other.
Initializing your widget in an MVC Area? Make sure to apply hotfix 12.0.6 where we fixed the following bug: “If the page builder was initialized in a controller of a page located in an MVC Area, an error was displayed instead of the content on the live site and when previewing the page.”
Don’t directly pass the property model to your widget views. Passing data to views is the responsibility of the widget's ViewModel, and we strongly recommend keeping the models separate.
Don’t forget to enable the page builder feature before developing MVC widgets.
Hopefully this breakdown of the MVC widgets and the additional notes for developers provided will prove helpful as you embark on your latest MVC adventure. We’re always here to help with any questions you may have through our support channels, and will continue releasing articles about MVC widgets in the coming weeks to give more examples to help guide you through the development of these components.