Showing posts with label JSONResult. Show all posts
Showing posts with label JSONResult. Show all posts

Tuesday, June 5, 2012

jqPlot Line with asp.net MVC 3

In this post we will be exploring using jqPlot line graph with asp.net MVC 3. Before starting with MVC, let’s see how line graph works. Let’s first download the plugin from-

http://www.jqplot.com/

To start with let’s see how line graph works. First let’s include the following file references-
<link class="include" rel="stylesheet" type="text/css" href="@Url.Content("~/scripts/jqplot/css/jquery.jqplot.min.css")" />
<!--[if lt IE 9]><script language="javascript" type="text/javascript" src="@Url.Content("~/scripts/jqplot/excanvas.min.js")"></script><![endif]-->
<script type="text/javascript" src="@Url.Content("~/scripts/jqPlot/jquery.jqplot.min.js")"></script>
<script type="text/javascript" src="@Url.Content("~/scripts/jqplot/jqplot.canvasTextRenderer.min.js")"></script>
<script type="text/javascript" src="@Url.Content("~/scripts/jqplot/jqplot.canvasAxisTickRenderer.min.js")"></script>
<script type="text/javascript" src="@Url.Content("~/scripts/jqplot/jqplot.dateAxisRenderer.min.js")"></script>
@*<script type="text/javascript" src="@Url.Content("~/scripts/jqplot/jqplot.highlighter.min.js")"></script>*@
For this demo we are going to use the following CSS-
<style type="text/css">
    .jqplot-point-label
    {
        white-space: nowrap;
    }
    div.jqplot-target
    {
        height: 400px;
        width: 750px;
        margin: 70px;
    }
    .tooltipCss
    {
        position: absolute;
        background-color: #b2b1ac;
        color: White;
        z-index: 200;
        padding: 5px;
        border-radius: 5px;
        display: none;
    }
</style>
Following is the code used to activate the line plugin-
<script type="text/javascript">
    $(document).ready(function () {
        var line1 = [['2/2/2008', 10], ['2/5/2008', 56], ['2/7/2008', 39], ['2/10/2008', 81], ['2/15/2008', 10], ['2/18/2008', 56], ['2/22/2008', 39], ['2/30/2008', 81]];
        var line2 = [['2/16/2008', 43], ['2/18/2008', 45], ['2/17/2008', 50], ['2/12/2008', 40], ['2/1/2008', 10], ['2/14/2008', 56], ['2/7/2008', 39], ['2/22/2008', 81], ['2/29/2008', 81]];
        var labels = [
                   { label: 'serie name 1', lineWidth: 1 },
                   { label: 'serie name 2', lineWidth: 1 }
                ];

        var plot2 = $.jqplot('chart1', [line1, line2], {
            series: labels,
            legend: {
                show: true,
                placement: 'outsideGrid'
            },
            //                highlighter: {
            //                    show: true,
            //                    showTooltip: true,
            //                    yvalues: 2,
            //                    formatString: '<table class="jqplot-highlighter"><tr><td>Point </td><td>"%s"</td></tr><tr><td>value </td><td>"%s"</td></tr><tr><td>Series </td><td>"%s"</td></tr></table>'
            //                },
            cursor: {
                show: true,
                tooltipLocation: 'sw'
            },
            axes: {
                xaxis: {
                    tickRenderer: $.jqplot.CanvasAxisTickRenderer,
                    renderer: $.jqplot.DateAxisRenderer,
                    label: 'Date',
                    tickOptions: {
                        angle: -15,
                        formatString: '%m/%d/%y'
                    }
                },
                yaxis: {
                    label: 'Value',
                    labelRenderer: $.jqplot.CanvasAxisLabelRenderer
                }
            }
        });

        $('#chart1').bind('jqplotDataMouseOver',
                    function (ev, seriesIndex, pointIndex, data) {
                        date = new Date(data[0]);
                        $('#info2').html('series "' + labels[seriesIndex].label + '" point "' + (date.getMonth() + 1) + "/" + (date.getDate() < 10 ? "0" + date.getDate() : date.getDate()) + "/" + date.getFullYear() + '"<br /> value "' + data[1] + '"');
                        $('#info2').css({ "left": ev.pageX + 3, "top": ev.pageY })
                        $('#info2').show();
                    }
                );
        $('#chart1').bind('jqplotDataUnhighlight',
                    function (ev) {
                        $('#info2').hide();
                    }
            );
    });
</script>
<div class="example-content">
    <div class="example-plot" id="chart1">
    </div>
</div>
<div id="info2" class="tooltipCss">
</div>
Here I am not going to explain the detail of the plugin. There are many options used in the plugin. Detail of various options can be found here-

http://www.jqplot.com/docs/files/jqPlotOptions-txt.html
http://www.jqplot.com/docs/files/optionsTutorial-txt.html

And we can use the options whatever serves our purpose. You can see some commented code in the plugin that is highlighter. There are many options available in the highlighter, but managing the tooltip HTML is not that great. So, I wish to use separate highlighter.

I have used the div with id info2 to hold the tooltip content. As you can, two events are attached to the plugin 'jqplotDataMouseOver' and 'jqplotDataUnhighlight' to deal with tooltip on the points on the line graph. First one is used for mouse over and the second one is used for mouse out.

If we check the input data to the plugin is nothing but an array of lines where each line is in turn array of points. Each point is intern is an array of two elements. First one is date and second is the value for that date.

So, if we want to implement using MVC is nothing but returning this data array. Also as you can see that we have used a separate array named labels to hold the names of the lines.

Model driven Line:

Let’s implement it with MVC 3. To start with let’s have the following model-
namespace Line.Models
{
    public class LineViewModel
    {
        public int id { get; set; }
        public string LineName { get; set; }
        public List<LineDataViewModel> data { get; set; } 
    }
    public class LineDataViewModel
    {
        public DateTime Date { get; set; }
        public double Value { get; set; }
    }
}
Everything is same as previous implementation except the data creation. Let’s first replace the first line of the plugin initialization by the following line-
var plot2 = $.jqplot('chart1', line, {
And also the view should accept the following model-
@model  List
Let’s now build the data array "line" and series "labels". Now gets generate some random data in action method and pass to the view like below-
        public ActionResult ModelDrivenLine()
        {
            Random r = new Random();
            List<LineViewModel> data = new List<LineViewModel>();
            
            LineViewModel l1 = new LineViewModel();
            l1.LineName = "First line";
            l1.id = 1;
            l1.data = new List<LineDataViewModel>();
            for (int i = 0; i < 10; i++)
                l1.data.Add(new LineDataViewModel() { Date = DateTime.Now.AddDays(r.Next(1, 25)), Value = r.Next(1, 10) });
            data.Add(l1);

            LineViewModel l2 = new LineViewModel();
            l2.LineName = "Second line";
            l2.id = 2;
            l2.data = new List<LineDataViewModel>();
            for (int i = 0; i < 10; i++)
                l2.data.Add(new LineDataViewModel() { Date = DateTime.Now.AddDays(r.Next(1, 25)), Value = r.Next(1, 10) });
            data.Add(l2);

            return View(data);
        }
Now we can generate the data by the following code-
        var line = new Array();
        var labels = new Array();
        @foreach (var m in Model)
        {
            <text>labels.push({label: "</text>@m.LineName<text>"}); 
            var line</text>@m.id<text> =new Array();</text>
            foreach (var l in m.data)
            {
                <text> line</text>@m.id<text>.push(["@l.Date.ToString("M/dd/yyyy")", @l.Value]);</text>
            }
            <text>line.push(line</text>@m.id<text>);</text>
        }
What we are doing is looping the model data and creating two required array. Here <text></text> is used to direct the razor engine to render the data as text. Line <text>labels.push({label: "</text>@m.LineName<text>"}); is used to create series name (the array for name of the lines(labels)). If you see the model there is a separate property as Id. This is used to uniquely identify each line. And you can see in line var line</text>@m.id<text> =new Array();</text> we are creating array for each line, so if id is one, the result of the line will be var line1 =new Array();. And with the next for loop we are pushing the line values to the corresponding array. And the next line we are adding the array to the final data array. That's all.

The result of the above code will look like-
        var line = new Array();
        var labels = new Array();
            labels.push({label: "First line"}); 
            var line1 =new Array();
                 line1.push(["6/21/2012", 2]);
                 line1.push(["6/15/2012", 8]);
                 line1.push(["6/06/2012", 9]);
                 line1.push(["6/13/2012", 2]);
                 line1.push(["6/09/2012", 2]);
                 line1.push(["6/15/2012", 8]);
                 line1.push(["6/09/2012", 5]);
                 line1.push(["6/13/2012", 8]);
                 line1.push(["6/23/2012", 5]);
                 line1.push(["6/12/2012", 1]);
            line.push(line1);
            labels.push({label: "Second line"}); 
            var line2 =new Array();
                 line2.push(["6/11/2012", 9]);
                 line2.push(["6/27/2012", 2]);
                 line2.push(["6/27/2012", 6]);
                 line2.push(["6/21/2012", 5]);
                 line2.push(["6/13/2012", 6]);
                 line2.push(["6/08/2012", 5]);
                 line2.push(["6/07/2012", 7]);
                 line2.push(["6/18/2012", 8]);
                 line2.push(["6/19/2012", 7]);
                 line2.push(["6/15/2012", 6]);
            line.push(line2);
        var plot2 = $.jqplot('chart1', line, {
Now if we want to use jQuery ajax to get data from the controller action and use it to the line graph. We can do it simply. We can have a view from the view we can do an ajax call to controller action. And the action method goes like below-
        public JsonResult AjaxLineJSON()
        {
            //This part is just like the previous action method
            return Json((from d in data
                select new {d.LineName,data= (from tl in d.data
                                         select new { Date= tl.Date.ToString("M/dd/yyyy"), Value=tl.Value}).ToList()}), JsonRequestBehavior.AllowGet);
        }
And the ajax call looks like-
<script type="text/javascript">
    $(document).ready(function () {
        $.ajax({
            type: "get",
            timeout: 30000,
            url: '@Url.Action("AjaxLineJSON")',
            dataType: "json",
            contentType: "application/json; charset=utf-8",
            success: function (result) {
                var line = new Array();
                var series = new Array();
                $(result).each(function (i, itm) {
                    series.push(itm.LineName);
                    line[i] = new Array();
                    $(itm.data).each(function (j, item) {
                        line[i].push([item.Date, item.Value])
                    });
                });
                //initialize the graph here.
        });
    });
</script>
That is all for now. You can download the code from here.

Thursday, May 24, 2012

Show/hide detail in a table using jQuery and MVC 3

This is another simple example where we will be showing some record in a table and there will be some plus/ minus image in each row and on click of the image we will be showing some detail of the record. And we will toggle the images and data. To do that lets have the following view models-
namespace MVCRazor.ViewModel
{
    public class TableRowItemViewlModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public TableRowItemDetailViewlModel Detail { get; set; }
    }
    public class TableRowItemDetailViewlModel
    {
        public string Address { get; set; }
        public string Sex { get; set; }
        public string Nationality { get; set; }
    }
}
The model is simple and self explanatory. And we are going to use the following view to display the tabular data and the controller to read the data. In the sample we have taken some in memory object for data access-
namespace MVCRazor.Controllers
{
    public class TableRowDetailController : Controller
    {
        List<TableRowItemViewlModel> data = new List<TableRowItemViewlModel>();
        public TableRowDetailController()
        {
            data.AddRange(new List<TableRowItemViewlModel>(){
            new TableRowItemViewlModel(){ Id =1,Name="Name 1", Email ="Email 1", Detail=new TableRowItemDetailViewlModel(){Address="Address 1", Nationality="Nationality 1", Sex="Sex 1"}},
            new TableRowItemViewlModel(){ Id =2,Name="Name 2", Email ="Email 2", Detail=new TableRowItemDetailViewlModel(){Address="Address 2", Nationality="Nationality 2", Sex="Sex 2"}},
            new TableRowItemViewlModel(){ Id =3,Name="Name 3", Email ="Email 3", Detail=new TableRowItemDetailViewlModel(){Address="Address 3", Nationality="Nationality 3", Sex="Sex 3"}},
            new TableRowItemViewlModel(){ Id =4,Name="Name 4", Email ="Email 4", Detail=new TableRowItemDetailViewlModel(){Address="Address 4", Nationality="Nationality 4", Sex="Sex 4"}},
            new TableRowItemViewlModel(){ Id =5,Name="Name 5", Email ="Email 5", Detail=new TableRowItemDetailViewlModel(){Address="Address 5", Nationality="Nationality 5", Sex="Sex 5"}},
            new TableRowItemViewlModel(){ Id =6,Name="Name 6", Email ="Email 6", Detail=new TableRowItemDetailViewlModel(){Address="Address 6", Nationality="Nationality 6", Sex="Sex 6"}},
            new TableRowItemViewlModel(){ Id =7,Name="Name 7", Email ="Email 7", Detail=new TableRowItemDetailViewlModel(){Address="Address 7", Nationality="Nationality 7", Sex="Sex 7"}},
            new TableRowItemViewlModel(){ Id =8,Name="Name 8", Email ="Email 8", Detail=new TableRowItemDetailViewlModel(){Address="Address 8", Nationality="Nationality 8", Sex="Sex 8"}},
            new TableRowItemViewlModel(){ Id =9,Name="Name 9", Email ="Email 9", Detail=new TableRowItemDetailViewlModel(){Address="Address 9", Nationality="Nationality 9", Sex="Sex 9"}},
        });
        }

        public ActionResult Index()
        {
            return View((from c in data
                         select new TableRowItemViewlModel() { Id = c.Id, Name = c.Name, Email = c.Email }).ToList());
        }
    }
}
@model List<MVCRazor.ViewModel.TableRowItemViewlModel>
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<style>
.tbl {border:1px solid gray; }
.tbl td{padding:5px 10px 5px 10px; }
.tbl th{padding:5px 10px 5px 10px;background-color:Gray;color:White }
.pm{ cursor:pointer;}
.plus
{
    background:url('http://www.quimicasuiza.com/images/extras/plus-minus.gif') 0 -16px;
    display:block;
    width:16px;
    height:16px;
}
.minus
{
    background:url('http://www.quimicasuiza.com/images/extras/plus-minus.gif') 0 0;
    display:block;
    width:16px;
    height:16px;
}
.detail
{
    background-color:#d4d0d8;    
    padding:7px;
}
</style>
<table class="tbl" cellpadding="0" cellspacing="0">
<tr><th>&nbsp;</th><th>Id</th><th>Name</th><th>Email</th></tr>
@foreach (var row in Model)
{ 
    <tr><td><span class="pm plus"></span></td><td>@row.Id</td><td>@row.Name</td><td>@row.Email</td></tr>
}
</table>
The above controller and the view will display the data like below-
We are going to use the following script to retrieve data from the controller and show hide the details.
<script type="text/javascript">
    var colCount;
    $(document).ready(function () {
        colCount = $(".tbl tr:first").children().length;
        $("tr:odd").css("background-color", "#f0f3f4");
        $(".pm").click(function () {
            if ($(this).hasClass("plus")) {
                $(this).removeClass("plus").addClass("minus");
                if (!$(this).closest("tr").next().hasClass("detail")) {
                    getDetail($(this).closest("tr"));
                }
                else
                    $(this).closest("tr").next().show();
            }
            else {
                if ($(this).closest("tr").next().hasClass("detail"))
                    $(this).closest("tr").next().hide();
                $(this).removeClass("minus").addClass("plus");
            }
        });
    });
    function getDetail(row) {
        var rowNew = $("<tr class='detail'><td colspan=" + colCount + "></td></tr>");
        $.ajax({
            type: "get",
            timeout: 30000,
            data: "id=" + row.find("td:eq(1)").html(),
            url: '@Url.Action("GetDetail")',
            dataType: "json",
            contentType: "application/json; charset=utf-8",
            success: function (result) {
                rowNew.find("td").append("<b>Address </b>: " + result.Address);
                rowNew.find("td").append("<br /><b>Sex </b>: " + result.Sex);
                rowNew.find("td").append("<br /><b>Nationality </b>: " + result.Nationality);
                row.after(rowNew);
            },
            error: function (a, b, c) {
                debugger;
            }
        });
    }
</script>
In this we are showing plus/minus button as span with CSS class pm. On click of the span we are checking whether it has a class named plus . Based on that in line 8 and 18 we are toggling the classes plus/minus.

If the line has class called plus, in the line 9 we are checking whether the next row of the container row has a CSS class called detail. Suppose it has that class then we are simply showing that row(in line 13). Otherwise we are calling a function called getDetail in line 10 by passing the current row. In that function we are building a row in memory with same columnspan as of the table row. Then we are passing the id of row and doing a ajax call to the controller to get the data. In the success of the ajax call we are adding the newly created row next to the current row(in line 37).

On click of span, if the condition check in the line 7 does not have a class named plus, that means the detail is already loaded and open. We are simply hiding the detail in line(16-17).

The controller method for getting detail is as follows-
        public JsonResult GetDetail(int id)
        {
            return Json((from c in data
                         where c.Id == id
                         select c.Detail).First(), JsonRequestBehavior.AllowGet);
        }
In the image we can see things in action. If we click the button multiple time, the ajax call will happen one time only. And on subsequent click it just show and hide the data.

Wednesday, February 29, 2012

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.