Click here to Skip to main content
15,867,992 members
Articles / Web Development / ASP.NET

Widgets in MVC

Rate me:
Please Sign up or sign in to vote.
4.88/5 (20 votes)
6 Jun 2013CPOL3 min read 83.9K   2.9K   52   14
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:

C#
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?

C#
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; }
    
}

Image 1

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.

C#
@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:

C#
@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/.

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

Image 2

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
C#
@{
    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:

C#
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:

C#
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:

Image 3

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

C#
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.

C#
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.

C#
@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: 

C#
@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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Bangladesh Bangladesh
I am a Sr.Software Engineer at Brain Station -23. I have 5+ years of work experience in .Net technology. I strongly believe that before software can be reusable it first has to be usable.

My contact info :

mfrony2003@yahoo.com
mfrony2003@hotmail.com

LinkedIn
http://www.linkedin.com/profile/view?id=106671466&trk=tab_pro

Comments and Discussions

 
QuestionDoes not sort Pin
longnights27-Jan-17 22:14
longnights27-Jan-17 22:14 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun16-Nov-14 18:01
Humayun Kabir Mamun16-Nov-14 18:01 
GeneralMy vote of 5 Pin
Amr Ellafy9-Oct-13 3:17
Amr Ellafy9-Oct-13 3:17 
GeneralRe: My vote of 5 Pin
Faisal(mfrony)10-Oct-13 5:23
Faisal(mfrony)10-Oct-13 5:23 
GeneralMy vote of 5 Pin
dgDavidGreene7-Jun-13 11:54
dgDavidGreene7-Jun-13 11:54 
GeneralMy vote of 5 Pin
Volynsky Alex6-Jun-13 9:34
professionalVolynsky Alex6-Jun-13 9:34 
Questioncan you provide CSS if it is possible.. Pin
Jitendra.Jadav3-Jun-13 23:33
Jitendra.Jadav3-Jun-13 23:33 
AnswerRe: can you provide CSS if it is possible.. Pin
Faisal(mfrony)4-Jun-13 2:30
Faisal(mfrony)4-Jun-13 2:30 
I actually Upload my project source code with that article but not sure why its not showing . Until correction if you need that can mail it to you. Give me the mail Address.
GeneralRe: can you provide CSS if it is possible.. Pin
Jitendra.Jadav4-Jun-13 2:39
Jitendra.Jadav4-Jun-13 2:39 
GeneralMy vote of 5 Pin
Jitendra.Jadav3-Jun-13 23:31
Jitendra.Jadav3-Jun-13 23:31 
GeneralMy vote of 5 Pin
Abolfazl_Rajabpour3-Jun-13 5:06
Abolfazl_Rajabpour3-Jun-13 5:06 
GeneralMy vote of 5 Pin
Marco Rinaldi3-Jun-13 3:48
Marco Rinaldi3-Jun-13 3:48 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun2-Jun-13 23:45
Humayun Kabir Mamun2-Jun-13 23:45 
QuestionOne request for code sample Pin
Tridip Bhattacharjee2-Jun-13 20:47
professionalTridip Bhattacharjee2-Jun-13 20:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.