Kentico EMS: MVC Widget Experiments Part 1 - Dynamic Views
Tags: kentico, aspnet, mvc, cms
Published: 2020-03-16 15:36:58

---
title: Kentico EMS: MVC Widget Experiments Part 1 - Dynamic Views
published: true
description: Learn how to make your Kentico MVC Widgets more flexible with dynamic views.
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/sh3r7n5fwjvyod66vf6f.jpg
tags: kentico, aspnet, mvc, cms
series: Kentico EMS - MVC Widget Experiments
---

<figcaption>Photo by <a href="https://unsplash.com/@halgatewood">Hal Gatewood
</a> on <a href="https://unsplash.com">Unsplash</a></figcaption>

## Widget Experiments

_This series dives into Kentico 12 MVC Widgets and the related technologies that are part of Kentico's Page Builder technology - Widget Sections, Widgets, Form Components, Inline Editors, and Dialogs 🧐._

_Join me 👋, as we explore the nooks and crannies of Kentico EMS MVC Widgets and discover what might be possible with this powerful technology..._

## Goals

This post is going to cover how we can create a Widget that changes its Razor view file dynamically (based on configuration) and why this functionality might be useful to both developers and content managers.

## Widgets and Views

The Kentico EMS documentation says a Widget can [switch between views](https://docs.kentico.com/k12sp/developing-websites/page-builder-development/developing-widgets-in-mvc#DevelopingwidgetsinMVC-Widgetswithacustomcontroller) when building a Widget using a custom controller, but what does this mean 🤔?

Normally, when building a Kentico MVC Widget, we create a new Razor partial view file in the `~/Views/Shared/Widgets` folder and name the file to match the name we use when registering the Widget:

```csharp
[assembly: RegisterWidget(
    "CompanyName.CustomWidget", 
    typeof(CustomWidgetController), 
    "Custom widget")]
```
<figcaption>From the <a href="https://docs.kentico.com/k12sp/developing-websites/page-builder-development/developing-widgets-in-mvc#DevelopingwidgetsinMVC-Registeringwidgets">Kentico docs</a></figcaption>

The Razor view for this `CustomWidget` would be created at `~/Views/Shared/Widgets/_CustomWidget.cshtml`, and we would help MVC find this view by specifying a part of the path in the Widget's Controller `Index()` method:

```csharp
return PartialView("Widgets/_CustomWidget", viewModel);
```

> This pattern relies somewhat on ASP.NET MVC's [convention-over-configuration](https://www.c-sharpcorner.com/article/software-design-paradigm-convention-over-configuration/) to find this file under `~/Views/Shared/Widgets/_CustomWidget`, since we only specified the last part of the path 🤓.

Note that there is no strict requirement that the Widget Identifier (`CompanyName.CustomWidget`) and the view name `_CustomWidget` match when creating a Widget with a custom controller - only when creating a [Basic Widget](https://docs.kentico.com/k12sp/developing-websites/page-builder-development/developing-widgets-in-mvc#DevelopingwidgetsinMVC-Basicwidgets).

However, it's a good convention to follow when creating a Widget with a custom controller with a single view (more on that later 😏).

## Example Widget: `CardWidget`

Let's create a "Card" Widget that we can use to explore the idea of dynamic Widget views.

![Card widget displayed in a browser. A black border surrounds an evenly spaced title, content, and call-to-action link](https://dev-to-uploads.s3.amazonaws.com/i/uxi0rbq5yo2j22oo8p0v.jpg)
<figcaption>This is what our initial Card Widget will look like with some <a href="https://getbootstrap.com/docs/4.4/components/card/">Bootstrap 4 Card Component</a> styles</figcaption>

First, lets create the view model class so we know what the controller needs to populate with data and what we need to render in the view:

```csharp
public class CardWidgetViewModel
{
    public string Title { get; set; }
    public string Content { get; set; }
    public string LinkUrl { get; set; }
    public string CallToAction { get; set; }
}
```

Then, we create the custom controller class, `CardWidgetController.cs`:

```csharp
public class CardWidgetController : WidgetController
{
    public ActionResult Index()
    {
        // Imagine 🧠 that this content came from the Document 
        //  in the Content Tree instead of being hard-coded here!

        var viewModel = new CardWidgetViewModel
        {
            Title = "Search our products",
            Content = "We have many items for sale",
            LinkUrl = "/products",
            CallToAction = "Search Now!"
        };

        return PartialView("Widgets/_CardWidget", viewModel);
    }
}
```

Next, we register the Widget so Kentico can expose it as an option in the Page Builder UI:

```csharp
[assembly: RegisterWidget(
    "Sandbox.CardWidget", typeof(CardWidgetController), "Card")]
```

Finally, we create a Razor view to render the view model contents:

```html
@model CardWidgetViewModel

<div class="card" style="width: 18rem;">
  <div class="card-body">
    <h5 class="card-title">@Model.Title</h5>
    <p class="card-text">@Model.Content</p>
    <a href="@Model.LinkUrl" class="card-link">@Model.CallToAction</a>
  </div>
</div>
```

## Configurable Design

This Widget looks nice 👍 and allows content editors to add this card of content anywhere on the site that has [Page Builder functionality enabled](https://docs.kentico.com/k12sp/developing-websites/page-builder-development).

However, our view's design is static.

If a content manager wants to re-use this content but change the way it appears, the way the Widget is currently built won't help 😔.

Imagine 🧠 that there are 2 ways, in our site's design, that this content can be displayed.

There's the original design we had above ✔:

![Original Card Widget UI rendered on a web page](https://dev-to-uploads.s3.amazonaws.com/i/4p3406u5i1y9m2cyd1ll.jpg)

And a wide, centered design with a header ✔:

![New Card Widget UI with a separate gray header containing the title, centered text and full page width](https://dev-to-uploads.s3.amazonaws.com/i/olf2qz8uhgdwta6nccsm.jpg)

We can allow content managers to choose a design for the content through [Widget Properties](https://docs.kentico.com/k12sp/developing-websites/page-builder-development/developing-widgets-in-mvc/defining-widget-properties-in-mvc), so let's add some.

> With most Widgets, exposing some configuration, through Widget Properties, for content managers is a good idea.

First, we create a Widget Properties class:

```csharp
public class CardWidgetProperties : IWidgetProperties
{
    [EditingComponent(
        RadioButtonsComponent.IDENTIFIER,
        DefaultValue = "Simple", Label = "Design")]
    [EditingComponentProperty(
        nameof(RadioButtonsProperties.DataSource),
        "Simple\r\nWide")]
    [Required]
    public string Design { get; set; }
}
```

Then, we update our controller class to inherit from the generic version of `WidgetController`:

```csharp
public class CardWidgetController : WidgetController<CardWidgetProperties>
```

Next, we use the `GetProperties()` method of the controller to get the properties and pass the value configured for the Widget to our view model:

```csharp
public ActionResult Index()
{
    CardWidgetProperties properties = GetProperties();

    var viewModel = new CardWidgetViewModel
    {
        Title = "Search our products",
        Content = "We have many items for sale",
        LinkUrl = "/products",
        CallToAction = "Search Now!",
        Design = properties.Design ?? "Simple"
    };

    return PartialView("Widgets/_CardWidget", viewModel);
}
```

Finally, we update our Razor view to render different HTML depending on the value of the `CardWidgetViewModel.Design` property:

```html
@model CardWidgetViewModel

@if (Model.Design == "Simple")
{
    <div class="card" style="width: 18rem;">
        <div class="card-body">
            <h5 class="card-title">@Model.Title</h5>
            <p class="card-text">@Model.Content</p>
            <a href="@Model.LinkUrl" class="card-link">@Model.CallToAction</a>
        </div>
    </div>
}
else if (Model.Design == "Wide")
{
    <div class="card text-center">
        <div class="card-header">
            @Model.Title
        </div>
        <div class="card-body">
            <p class="card-text">@Model.Content</p>
            <a href="@Model.LinkUrl" class="card-link">@Model.CallToAction</a>
        </div>
    </div>
}
else if (Context.Kentico().PageBuilder().EditMode)
{
    <h3>The selected "Design" (@Model.Design) of this widget
        is not supported.</h3>
}
```

What we end up with is a dialog in the Page Builder UI that allows us to toggle which of the two layouts we want to use:

![EMS Page Builder UI dialog with radio button options "Simple" and "Wide"](https://dev-to-uploads.s3.amazonaws.com/i/rmaeq06uq9v1vt3usgr9.jpg)

Awesome! We did it 👏! Our Widget displays content with a nice design and can be configured to use 2 different layouts...

Except now we've been asked to support another 4 layouts, all meant for different areas of a page and parts of our site... 😱

At some point the `@if(...) { }` and `elseif(...) { }` blocks are going to become complex, hard to read, and will distract from the HTML - not that different from a giant C# class with many if/else conditionals.

How can we resolve this 🤔?

## Dynamic Views

Instead of varying the markup in a single view, based on the value of the `CardWidgetViewModel.Design` property, we can choose to render different Razor views based on how the Widget properties have been configured 🤯!

We're going to work backwards, since we know our goal is simplify the Razor view files.

First, we create a new folder `~/Views/Shared/Widgets/Card/` and move our `_CardWidget.cshtml` file into this folder.

We will also copy that file and rename both so we end up with `_Simple.cshtml` and `_Wide.cshtml`:

![Visual Studio solution tree showing two new files under the paths ~/Views/Shared/Widgets/Card/_Simple.cshtml and ~/Views/Shared/Widgets/Card/_Wide.cshtml](https://dev-to-uploads.s3.amazonaws.com/i/mzsa1ju0ne8359o3iooo.jpg)

Both view files will only contain the markup needed for design it represents, and both still use the same view model class, `CardWidgetViewModel`:

```html
<!-- _Simple.cshtml -->

@model CardWidgetViewModel

<div class="card" style="width: 18rem;">
    <div class="card-body">
        <h5 class="card-title">@Model.Title</h5>
        <p class="card-text">@Model.Content</p>
        <a href="@Model.LinkUrl" class="card-link">@Model.CallToAction</a>
    </div>
</div>
```

```html
<!-- _Wide.cshtml -->

@model CardWidgetViewModel

<div class="card text-center">
    <div class="card-header">
        @Model.Title
    </div>
    <div class="card-body">
        <p class="card-text">@Model.Content</p>
        <a href="@Model.LinkUrl" class="card-link">@Model.CallToAction</a>
    </div>
</div>
```

Next, we can remove the `Design` property from the `CardWidgetViewModel` class:

```csharp
public class CardWidgetViewModel
{
    public string Title { get; set; }
    public string Content { get; set; }
    public string LinkUrl { get; set; }
    public string CallToAction { get; set; }
}
```

Finally, we will update our Widget controller class to pick the correct view based on the selected Widget Properties value:

```csharp
public ActionResult Index()
{
    var properties = GetProperties();

    var viewModel = new CardWidgetViewModel
    {
        Title = "Search our products",
        Content = "We have many items for sale",
        LinkUrl = "/products",
        CallToAction = "Search Now!",
    };

    return PartialView($"Widgets/Card/_{properties.Design}", viewModel);
}
```

Now, our Widget will function exactly the same, but we have much more maintainable Razor view files 💪🏾!

This will be especially important if the overall layout isn't the only thing that needs to be customizable about the Widget.

For example, we could expose Widget Properties for border color, text color, call-to-action design, ect...

Each additional configuration adds complexity to the views because markup will need to be rendered conditionally.

However, by separating our views into different high-level layout files, we help to decrease the growing complexity 🤗.

## Conclusion

MVC Widgets with configurable designs are appealing to developers and content managers since they make content reusable and reduce repetitive HTML.

Dynamic views are an easy way to make these kinds of Widgets more maintainable for developers since they abstract different layouts into separate files.

They can help scale and manage the complexity of MVC Widgets in our applications.

This mirrors how we make our C# code more maintainable by breaking larger classes and methods into smaller ones 🧐.

As always, thanks for reading 🙏!

---

We've put together a list over on [Kentico's GitHub account](https://github.com/Kentico/Home/blob/master/RESOURCES.md) of developer resources. Go check it out!

If you are looking for additional Kentico content, checkout the Kentico tag here on DEV:

{% tag kentico %}

Or my Kentico blog series:

- [Kentico 12: Design Patterns](https://dev.to/search?q=Kentico%2012%3A%20Design%20Patterns)
- [Kentico CMS Quick Tips](https://dev.to/search?q=Kentico%20CMS%20Quick%20Tip)