Wednesday, February 29, 2012

Posting list of text box values to array or list using MVC 3

Lets describe the problem with example. Lets have the following model and view-
    public class SampleDataModel
    {
        public string Data1 { get; set; }
        public string Data2 { get; set; }
        public string Data3 { get; set; }
        public string Data4 { get; set; }
        public string Data5 { get; set; }
        public string Data6 { get; set; }
    }
@model razor.Models.SampleDataModel

@using (Html.BeginForm())
{
    @Html.TextBoxFor(x => x.Data1) <br />   
    @Html.TextBoxFor(x => x.Data2)<br />
    @Html.TextBoxFor(x => x.Data3)<br />
    @Html.TextBoxFor(x => x.Data4)<br />
    @Html.TextBoxFor(x => x.Data5)<br />
    @Html.TextBoxFor(x => x.Data6)<br />
    <input type="submit" value="Submit data" />
}
Now if we have a controller action method like-
        [HttpPost]
        public ActionResult Posting_list_of_text_to_array_or_list(razor.Models.SampleDataModel data)
        {
            return PartialView("Success");
        }
Then data will get posted properly. Mow suppose in some case we need to post the data to a string array(string[]) or to generic list(List<string>), then how we can do that using the same view.

Its very simple. Lets first check the generated HTML for the view.
<form method="post" action=/BlogPost/Posting_list_of_text_to_array_or_list?X-Requested-With=XMLHttpRequest>
<input id="Data1" type="text" name="Data1"><br>
<input id="Data2" type="text" name="Data2"><br>
<input id="Data3" type="text" name="Data3"><br>
<input id="Data4" type="text" name="Data4"><br>
<input id="Data5" type="text" name="Data5"><br>
<input id="Data6" type="text" name="Data6"><br>
<input value="Submit data" type="submit">
</form>
If we see the HTML, the name of the input box is same as the id of the input box. There is one beauty of the default model binder in MVC 3 that if it finds some form fields with the same name then it try to convert it collection or array. So, we can achieve by changing the name of the input box to the parameter name of the controller action like below-
@model razor.Models.SampleDataModel

<script type="text/javascript">
    $(document).ready(function () {
        $(".similar").attr("name", "data");
    });
</script>

@using (Html.BeginForm())
{
    @Html.TextBoxFor(x => x.Data1, new { @class = "similar" }) <br />   
    @Html.TextBoxFor(x => x.Data2, new { @class = "similar" })<br />
    @Html.TextBoxFor(x => x.Data3, new { @class = "similar" })<br />
    @Html.TextBoxFor(x => x.Data4, new { @class = "similar" })<br />
    @Html.TextBoxFor(x => x.Data5, new { @class = "similar" })<br />
    @Html.TextBoxFor(x => x.Data6, new { @class = "similar" })<br />
    <input type="submit" value="Submit data" />
}
What is done here is simple. Added a CSS class to the text boxes and using jQuery we have set the name attribute of the text boxes to a same value. Now if we add a action method like-
        [HttpPost]
        public ActionResult Posting_list_of_text_to_array_or_list(List data)
        {
            return PartialView("Success");
        }
or
        [HttpPost]
        public ActionResult Posting_list_of_text_to_array_or_list(string[] data)
        {
            return PartialView("Success");
        }
The values of the text boxes will get posted without any issue.

Posting an array or generic list of string to asp.net MVC 3 using jQuery ajax

This is a simple post that we will be using to post an array of value type or a generic list of value. We will be using string[] and List for our example. Lets have a vary basic controller action method that will be used for this purpose
        [HttpPost]
        public JsonResult Binding_posting_to_Array_or_List(string[] data)
        {
            return Json("success");
        }
Or
        [HttpPost]
        public JsonResult Binding_posting_to_Array_or_List(List data)
        {
            return Json("success");
        }
Now lets have a sample jQuery code to call the controller method as below-
 <script type="text/javascript">
    $(document).ready(function () {
        $("#btn").click(function () {
            $.ajax({
                url: '@Url.Action("Binding_posting_to_Array_or_List")',
                type: 'POST',
                data: { data: ["value 1", "value 2", "value 3"] },
                dataType: "json",
                success: function (response) {
                    alert(response);
                },
                error: function (xhr) {
                    debugger;
                    alert(xhr);

                }
            });
        });
    });
</script>
<input type="button" id="btn" value="Save data" />
But if we check the posted value at runtime in controller, we will find null value got posted-


The reason is MVC expects the data in querystring pattern. And we are passing data as a JSON object. The code will work if we pass data as querystring-
data: 'data=value 1&data=value 2&data=value 3',
Now jQuery ajax has a built in feature to solve this problem. That is the use of traditional option in the ajax call. If we pass the data as JSON object and set the option traditional:true,, jQuery will internally convert input data in querystring format. jQuery ajax method does this by using jQuery.param() API method. So, the final working sample of ajax call is as below-
 <script type="text/javascript">
     $(document).ready(function () {
        $("#btn").click(function () {
            $.ajax({
                url: '@Url.Action("Binding_posting_to_Array_or_List")',
                type: 'POST',
                traditional:true,
                data: {data:["value 1", "value 2", "value 3"]},
                dataType: "json",
                success: function (response) {
                    alert(response);
                },
                error: function (xhr) {
                    debugger;
                    alert(xhr);

                }
            });
        });
    }); 
</script>
Following image shows how the value gets converted to querystring format after using traditional option in the ajax call. This image is taken during run time using Firefox.


Thursday, February 23, 2012

Using msDropDown with tooltips plugin

In this post we are going to discuss using msDropDown plugin with tooltips plugin. First lets study the post for how to use msDropDown here. We are going to use the source code specified in that code.

To continue with tooltips implementation with msDropDown, we can first explore the generated HTML for the dropdown in the previous post.
First part(part 1) of the image is the UI of the rendered dropdown. Second part(part 2) is the actual dropdwn we have . And the third part(part 3) of the image is the generated HTML by the msDropDown plugin. Lets study the HTML a little.

If we notice the HTML generated in part 2, the select is inserted in a div and the div height is made to zero. So, the actual dropdown is made hidden. And if we notice the part 3 HTML, we can see the select got converted to a div which contains two child divs. The red box contains the HTML for the selected option. And the green box contains the all options. Each option has converted to anchor(<a> tag) with id like selectID_msa_index. If we notice we can see that each index corresponds to the index of corresponding select option.

Now adding tooltips to the select > option is nothing but adding tooltips to the anchor tag. Let us implement tooltips now. First let us add some dummy attribute to the option tag that represent the tooltip. In this case we are using attribute named tooltipdata like below-
<select name="webmenu" id="webmenu">
        <option value="calendar" tooltipdata="Calendar tip" title="http://www.marghoobsuleman.com/mywork/jcomponents/image-dropdown/samples/icons/icon_calendar.gif">
            Calendar</option>
        <option value="shopping_cart" tooltipdata="Shopping Cart tip" title="http://www.marghoobsuleman.com/mywork/jcomponents/image-dropdown/samples/icons/icon_cart.gif">
            Shopping Cart</option>
        <option value="cd" tooltipdata="CD tip" title="http://www.marghoobsuleman.com/mywork/jcomponents/image-dropdown/samples/icons/icon_cd.gif">
            CD</option>
        <option value="email" selected="selected" tooltipdata="Email tip" title="http://www.marghoobsuleman.com/mywork/jcomponents/image-dropdown/samples/icons/icon_email.gif">
            Email</option>
        <option value="faq" tooltipdata="FAQ tip" title="http://www.marghoobsuleman.com/mywork/jcomponents/image-dropdown/samples/icons/icon_faq.gif">
            FAQ</option>
        <option value="games" tooltipdata="Games tip" title="http://www.marghoobsuleman.com/mywork/jcomponents/image-dropdown/samples/icons/icon_games.gif">
            Games</option>
    </select>
Before implementing tooltip, we need to add the following file references-
<script src="http://jquery.bassistance.de/tooltip/jquery.tooltip.js" type="text/javascript"></script>
    <link href="http://jquery.bassistance.de/tooltip/jquery.tooltip.css" rel="stylesheet"
        type="text/css" />
Now lets modify the msDropDown plugin initialization code. If we go to the plugin documentation we can see that the plugin can accept a function as a parameter that gets called after the plugin initialization happens. So we can add a function like-
<script language="javascript">
        $(document).ready(function (e) {
            try {
                $("#webmenu").msDropDown({ onInit: callAfterInitialization });
            } catch (e) {
                alert(e.message);
            }
        });
        function callAfterInitialization() {
        }
    </script>
In our case we are we are adding a function named callAfterInitialization to onInit parameter of the msDropDown plugin.

Next we can use this function to implement tooltips plugin. As we have already seen the id of the generated anchor selectID_msa_index, we can get the index from the id and find corresponding option from the select. If we can get the option from the select then we can read the value attribute toolltipdata from the option, which is nothing but the tooltip text we need to show in the tooltip of the anchor. We can to this by the following selector. Here this is nothing but the anchor.
$("select[id*=webmenu] option:eq(" + 
this.id.substring(this.id.lastIndexOf("_") + 1) + ")").attr("tooltipdata");
So the full function definition goes like below-
        function callAfterInitialization() {
            $("a[id*=webmenu]").tooltip({
                track: true,
                delay: 0,
                showURL: false,
                fade: 250,
                bodyHandler: function () {
                    return $("select[id*=webmenu] option:eq(" + this.id.substring(this.id.lastIndexOf("_") + 1) + ")").attr("tooltipdata");
                },
                showURL: false
            });
        }
And finally to make sure the tooltip is always on the top, we can change the z-index property of the tooltip to a very higher value.
<style>
        div#tooltip
        {
            z-index: 20000;
        }
    </style>
In this case the tooltip is nothing but a div with id tooltip. You have to check the generated id for your tooltip.

Now if we want to add tooltip to selected item, we can achieve it with little more effort. If we notice part 3, red square section is the HTML for the selected item. The container has a css class named ddTitle. To add tooltip to the selected item is nothing but adding tooltip to the div with class ddTitle. We can do this by enabling tooltip for ddTitle inside document.ready. Code goes here-
$("div[id*=_msdd] div.ddTitle").tooltip({
                track: true,
                delay: 0,
                showURL: false,
                fade: 250,
                bodyHandler: function () {
                    return $("select[id*=" + this.id.substring(0, this.id.indexOf("_") - 1) + "] option:selected").attr("tooltipdata");
                },
                showURL: false
            });
What we are doing in bodyHandler is finding the selected option in the original drop down and adding it as the body of the tooltip. While selected index changes, the msDropDown plugin is also internally changing the selected index of the hidden drop down.

Using msDropDown - a dropdown with icon in the option

msDropDown is a nice plugin. Its a dropdown plugin where we can use icon with the option of the select element. The detail of the plugin can be found here. Implementation goes like below-

We need to add the jQuery and msDropDown script and css file reference. We can download the files form the plugin site given above.
    <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.js" type="text/javascript"></script>
    <script src="http://www.marghoobsuleman.com/mywork/jcomponents/image-dropdown/samples/msdropdown/js/jquery.dd.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="http://www.marghoobsuleman.com/mywork/jcomponents/image-dropdown/samples/msdropdown/dd.css" />
Working principle of the plugin is very simple. We need to add the icon path to the title of the option in select tag. Like below-
<option value="value" title="path of the icon">text</option>
Lets have a sample dropdown for this-
    <select name="webmenu" id="webmenu" onchange="showValue(this.value)">
        <option value="calendar" title="http://www.marghoobsuleman.com/mywork/jcomponents/image-dropdown/samples/icons/icon_calendar.gif">
            Calendar</option>
        <option value="shopping_cart" title="http://www.marghoobsuleman.com/mywork/jcomponents/image-dropdown/samples/icons/icon_cart.gif">
            Shopping Cart</option>
        <option value="cd" title="http://www.marghoobsuleman.com/mywork/jcomponents/image-dropdown/samples/icons/icon_cd.gif">
            CD</option>
        <option value="email" selected="selected" title="http://www.marghoobsuleman.com/mywork/jcomponents/image-dropdown/samples/icons/icon_email.gif">
            Email</option>
        <option value="faq" title="http://www.marghoobsuleman.com/mywork/jcomponents/image-dropdown/samples/icons/icon_faq.gif">
            FAQ</option>
        <option value="games" title="http://www.marghoobsuleman.com/mywork/jcomponents/image-dropdown/samples/icons/icon_games.gif">
            Games</option>
    </select>
Now we can activate the msDropDown by the following JavaScript code-
    <script language="javascript">
        $(document).ready(function (e) {
            try {
                $("#webmenu").msDropDown();
            } catch (e) {
                alert(e.message);
            }
        });
    </script>
Thats all. For various other options we can check the plugin site.

Wednesday, February 1, 2012

Full Calendar with JSON data source using asp.net web service/ pagemethod/ webmethod

In this blog post we are going to discuss using full calendar plugin with JSON data source through asp.net webservice / pagemethod / webmethod. We can get the detail of the plugin here.

For using this plugin we need to add the reference of the following files-
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.min.js" type="text/javascript"></script>
    <link rel='stylesheet' type='text/css' href='http://arshaw.com/js/fullcalendar-1.5.2/fullcalendar/fullcalendar.css' />
    <script type='text/javascript' src='http://arshaw.com/js/fullcalendar-1.5.2/jquery/jquery-ui-1.8.11.custom.min.js'></script>
    <script type='text/javascript' src='http://arshaw.com/js/fullcalendar-1.5.2/fullcalendar/fullcalendar.min.js'></script>
Basic style HTML infrastructure using for this implementation is as follows-
        #loading
        {
            width: 600px;
            height: 550px;
            position: absolute;
            background-color: gray;
            color: white;
            text-align: center;
            vertical-align: middle;
            display: table-cell;
        }
        #fullcal
        {
            width: 600px;
            height: 600px;
            position: absolute;
            display: none;
        }
    <div>
        <div id="loading">
            <label style="top: 50%; position: relative">
                loading events....</label>
        </div>
        <div id="fullcal">
        </div>
    </div>
In the div with id fullcal we will be loading the calendar control. By default this div is marked as hidden, and a place holder div (with id loading) is added in the place. This is just to show while server data is getting loaded from server. Once the data is loaded on the calendar we will show back the calendar and hide the placeholder.

The script used for activating calendar is as follows-
    $('div[id*=fullcal]').fullCalendar({
        header: {
            left: 'prev,next today',
            center: 'title',
            right: 'month,agendaWeek,agendaDay'
        },
        editable: true,
        events: list of event here
    });
Now in full calendar the event object has lots of information. We can get more information about the event object here. Lets represent the event as a C# class as follows-
public class Event
{
    public int EventID { get; set; }
    public string EventName { get; set; }
    public string StartDate { get; set; }
    public string EndDate { get; set; }
}
There are many other properties for the event object. For the sack of implementation we are taking these only. And I think the class properties are self explanatory. We can get the data for the event from database. For this post we are creating in memory object for data source. The page method used for data retrieval is as follows-
   [WebMethod]
    public List GetEvents()
    {
        List events = new List();
        events.Add(new Event()
        {
            EventID = 1,
            EventName = "EventName 1",
            StartDate = DateTime.Now.ToString("MM-dd-yyyy"),
            EndDate = DateTime.Now.AddDays(2).ToString("MM-dd-yyyy")
        });
        events.Add(new Event()
        {
            EventID = 2,
            EventName = "EventName 2",
            StartDate = DateTime.Now.AddDays(4).ToString("MM-dd-yyyy"),
            EndDate = DateTime.Now.AddDays(5).ToString("MM-dd-yyyy")
        });
        events.Add(new Event()
        {
            EventID = 3,
            EventName = "EventName 3",
            StartDate = DateTime.Now.AddDays(10).ToString("MM-dd-yyyy"),
            EndDate = DateTime.Now.AddDays(11).ToString("MM-dd-yyyy")
        });
        events.Add(new Event()
        {
            EventID = 4,
            EventName = "EventName 4",
            StartDate = DateTime.Now.AddDays(22).ToString("MM-dd-yyyy"),
            EndDate = DateTime.Now.AddDays(25).ToString("MM-dd-yyyy")
        });
        return events;
    }
Now we can read the web service data using jQuery and fill the full calendar using server driven event list like following-
    $.ajax({
        type: "POST",
        contentType: "application/json",
        data: "{}",
        url: "FullcalenderwithWebservice.asmx/GetEvents",
        dataType: "json",
        success: function(data) {
            $('div[id*=fullcal]').fullCalendar({
                header: {
                    left: 'prev,next today',
                    center: 'title',
                    right: 'month,agendaWeek,agendaDay'
                },
                editable: true,
                events: data.d
     });
            $("div[id=loading]").hide();
            $("div[id=fullcal]").show();
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            debugger;
        }
    });
Now here is a slight problem, the calendar will get loaded but not the list of events returned. Few points we need to remember here-
  1.  The full calendar event object has certain naming like EventID should be id, EventName – title, StartDate – start, EndDate – end and so on. So, we have to map the returned object to full calendar’s desired object.
  2. One more thing that we need to remember is that the start and end need to be in date type. The proper conversation is as follows-
    $('div[id*=fullcal]').fullCalendar({
        header: {
            left: 'prev,next today',
            center: 'title',
            right: 'month,agendaWeek,agendaDay'
        },
        editable: true,
        events: $.map(data.d, function(item, i) {
                    var event = new Object();
                    event.id = item.EventID;
                    event.start = new Date(item.StartDate);
                    event.end = new Date(item.EndDate);
                    event.title = item.EventName;
                    return event;
                })
    });
We can note one more thing that we are returning the date in MM-dd-yyyy format (DateTime.Now.ToString("MM-dd-yyyy")). The reason is that we can pass such a string to Date constructor in JavaScript to create the date.

We can download the full source code from here.