Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Widgets in MVC

0.00/5 (No votes)
6 Jun 2013 1  
Easily build widgets in MVC with Razor View

Introduction

This article will help you to build a manageable widget using MVC4 with Razor view. This is not a fully technical article, it will give you a clear concept about the importance of architectural design while building a custom component or feature for our product. Here I will show you the use of a nested partial view that depends on abstraction and also has the extendibility feature.

Using the code 

Widgets are very familiar to us. Most sites have this feature with them. It is very important for users to get information in a single view so that s/he can plan their work very easily when logging into the site. So widgets can contain information from many sources. Suppose your company gives you the responsibility to design such a widget module that can be easily plugged with the model and is also dynamic. Here I will discuss the design concept about this type of requirement. Suppose we are building a notice board widget. Here I am using the interface for building that widget. I have two main interfaces on this design:

  1. IWidget.cs
  2. ISubWidget.cs

You may ask why two Interfaces, isn't IWidget enough?

Answer: This is because we need a dynamic widget.

Look at the details here:

public interface ISubWidget
{
    string Topic { get; set; }
    string Description { get; set; }
} 

public  interface IWidget
{
    int SortOrder { get; set; }
    string ClassName { get; set; }
    string FooterText { get; set; }
    string HeaderText { get; set; }
    ISubWidget SubWidget { get; set; }
}  

So here IWidget has a property SubWidget and its return type is ISubwidget. Now our IWidget works like a package for us. So our task is to build to a NoticeBoard Widget, right?

public class NoticeBoard : IWidget
{
    public int SortOrder { get; set; }
    public string ClassName { get; set; }    
    public string FooterText { get; set; }    
    public string HeaderText { get; set; }    
    public ISubWidget SubWidget { get; set; }        
}

public class SubWidget : ISubWidget
{
    public string Topic { get; set; }        
    public string Description { get; set; }
    
}

Fig 1.1: Dependency Structure of Concrete widgets

We build the widget in classes, now we need to attach it with the MVC application. Before showing the model population I want to show you the design concept for the views. We will use the partial view here. As  interfaces we have the same partial view:

  1. _Widget.cshtml
  2. _SubWiget.cshtml  

Razor view for _Widget.cshtml will populate the IWidget model and also load the ISubwidget into its body part. For both of them View/Shared/Widget/ is this path.

@model  MvcWidgetBuilder.Models.IWidget
 
<div class="widget">
    <div class="@Model.ClassName">
 
        <div class="header">
            @Model.HeaderText
        </div>
        <div class="body">
 
            @Html.Partial(string.Concat(new[] { "Widget", 
              "/", "_SubWidget" }), @Model.SubWidget)
 
        </div>
        <div class="footer">
            @Model.FooterText
        </div>
    </div>
</div>

The Razor view for _SubWidget.cshtml will populate the ISubWidget model:

@model  MvcWidgetBuilder.Models.ISubWidget
<div class="body">
    <div>
        <div style="float: left">
            @Html.LabelFor(p => p.Topic, @Model.Topic)
        </div>
    </div>
    <div style="clear: both">
        @Model.Description
    </div>
</div>

So we build our partial views. Who will call them to load them into the browser? We have another view to do this job:

  • _WidgetContainer.cshtml

I will just pass the model IWidget to the partial view _Widget.cshtml. The path of this view is same as before: View/Shared/Widget/.

@model  MvcWidgetBuilder.Models.IWidget
 
@foreach (MvcWidgetBuilder.Models.IWidget wm in ViewBag.Widgets)
{
    
    @Html.Partial(string.Concat(new[] { "Widget", "/", "_Widget" }), wm)
}

Fig. 1.2: Graphical picture of a partial view

So we have three partial views. We will now introduce a view for NoticeBoard.

  • NoticeBoard.cshtml (path: View/NoticeBoard/)
  • It calls the widgetcontainer
@{
    ViewBag.Title = "Widget";
}
 
@Styles.Render("~/Style/Widget.css")
<h2>Widget</h2>
 
<p>
    @{
        
        @Html.Partial("Widget/_WidgetContainer");
    }
</p>

and the controller for NoticeBoard is NoticeBoardController. The code for the controller is:

public class NoticeBoardController : Controller
{
    //
    // GET: /Widget/

    public ActionResult Index()
    {
            return View();
    }

    public ActionResult MyNoticeBoard()
    {
        ViewBag.Widgets = GetWidgetData();
        return View();
    }

When I call /NoticeBoard/MyNoticeBoard, it just populates ViewBag.Widgets by calling the below function:

public List<IWidget> GetWidgetData()
{
    var noticeboardWidget = new List<IWidget>
    {
        new NoticeBoard()
        {
         SortOrder = 1, ClassName = "high", 
           HeaderText = "Notice Board", FooterText = "" ,
         SubWidget = new SubWidget { Topic = "Office Time", 
           Description = "Office time will be change next month" },
        },
        new NoticeBoard()
        {
        SortOrder = 4, ClassName = "medium", 
          HeaderText = "Notice Board", FooterText = "" ,
        SubWidget = new SubWidget { Topic = "Salary", 
          Description = "Salary is dusburst plese check your account" },
        },
        new NoticeBoard()
        {
         SortOrder = 8, ClassName = "low", 
           HeaderText = "Notice Board", FooterText = "" ,
         SubWidget = new SubWidget { Topic = "About Lunch", 
           Description = "We need the feed back from you about the luch" },
        },              
        new NoticeBoard()
        {
         SortOrder = 2, ClassName = "high", 
           HeaderText = "Notice Board", FooterText = "" ,
         SubWidget = new SubWidget { Topic = "Emergency Meeting", 
           Description = "All  the managers please come to our meeting room by 11.30" },
        },
        new NoticeBoard()
        {
         SortOrder = 5, ClassName = "medium", 
           HeaderText = "Notice Board", FooterText = "" ,
         SubWidget = new SubWidget { Topic = "Office Meetting", 
           Description = "Todays meeting is cancel" },
        },
        new NoticeBoard()
        {
         SortOrder = 7, ClassName = "low", HeaderText = "Notice Board", FooterText = "" ,
         SubWidget = new SubWidget { Topic = "HoliDay Notice", 
           Description = "We shifted our holiday leave for 1 day" },
        },              
        new NoticeBoard()
        {
         SortOrder = 3, ClassName = "high", HeaderText = "Notice Board", FooterText = "" ,
         SubWidget = new SubWidget { Topic = "Vacancy", 
           Description = "We need a sound asp.net developer with C#" },
        },
        new NoticeBoard()
        {
         SortOrder = 6, ClassName = "medium", HeaderText = "Notice Board", FooterText = "" ,
         SubWidget = new SubWidget { Topic = "HR Notice", 
           Description = "Visiting cards proof send to you mail please check" },
        },
    };
 
    return noticeboardWidget;
}

In browser you will see the below screen:

But if you just change the return by sort order, it just rearranges.

return noticeboardWidget.OrderBy(p=>p.SortOrder).ToList()

Points of Interest

Here my concern is not to show you the CSS or the MVC Razor with the partial view. I just try to focus on the dynamic Widgets design. As  we can pass the class names too, we can control the CSS or view by model. Our widget views (partial views) are not dependent on the models (notice board) but on abstraction (IWidget). So if our company wants to categorise the model such ass HRNotice, SalesNotice, EmployeeNotice, we can easily do that by implementing IWidget. Those who are beginners can easily feel the importance of the interface because many times I see that people can not even answer the simple question "Why do we need interface?" I hope they find the basic answer from this article.

Another point  may come to your mind: What if I want to build a different widget than _Widget and _SubWidget? Does our IWidget support that?

Answer: No, but if we want to make it more dynamic we can do it easily by passing the view name.

public interface ISubWidget
{
    string Topic { get; set; }
    string Description { get; set; }
    string WidgetName { get; set; } <---------------
}

public  interface IWidget
{
    int SortOrder { get; set; }
    string ClassName { get; set; }
    string FooterText { get; set; }
    string HeaderText { get; set; }
    string WidgetName { get; set; } <-------
    ISubWidget SubWidget { get; set; }
}

Change on our views as well to load the dynamic view on _WidgetContainer.

@model  MvcWidgetBuilder.Models.IWidget
 
@foreach (MvcWidgetBuilder.Models.IWidget wm in ViewBag.Widgets)
{
    
    @Html.Partial(string.Concat(new[] { "Widget", "/", wm.WidgetName }), wm)
}

Below code is for our dynamic widget: 

@model  MvcWidgetBuilder.Models.IWidget
 
<div class="widget">
    <div class="@Model.ClassName">
 
        <div class="header">
            @Model.HeaderText
        </div>
        <div class="body">
 
            @Html.Partial(string.Concat(new[] { "Widget", "/", 
              @Model.SubWidget.WidgetName }), @Model.SubWidget)
 
        </div>
        <div class="footer">
            @Model.FooterText
        </div>
    </div>
</div>

Did you notice how simple it is a change on our design structure makes our models more dynamic. This is possible only because my modules depend on abstraction not on concrete types.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here