Search code examples
jqueryasp.net-mvcjqxgridjqwidget

Return Json from Action method prints the json on page instead of showing on grid control


I am trying to run the demo of JQWidgets by following the instructions in this link. But when I run the demo, I simply get the json printed on the webpage like this.

enter image description here

Here is my HomeController.cs

using JQWidgetGrids.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace JQWidgetGrids.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewData["Message"] = "Welcome to ASP.NET MVC!";

            return View();
        }

        public ActionResult DataHandler()
        {
            List<Employee> employees = EmployeesRepository.GetEmployees();

            return Json(new
            {
                employees
            },
            JsonRequestBehavior.AllowGet);
        }

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

Here is the DataHandler view

@{
    ViewBag.Title = "DataHandler";
}

<title><asp:ContentPlaceHolder ID="TitleContent" /></title>
<link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="~/Content/jqx.base.css" type="text/css" />
<script type="text/javascript" src="~/Scripts/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="~/Scripts/jqxcore.js"></script>
<script type="text/javascript" src="~/Scripts/jqxdata.js"></script>
<script type="text/javascript" src="~/Scripts/jqxbuttons.js"></script>
<script type="text/javascript" src="~/Scripts/jqxscrollbar.js"></script>
<script type="text/javascript" src="~/Scripts/jqxmenu.js"></script>
<script type="text/javascript" src="~/Scripts/jqxgrid.js"></script>
<script type="text/javascript" src="~/Scripts/jqxgrid.selection.js"></script>

<h2>DataHandler</h2>

<script type="text/javascript">
    $(document).ready(function () {
        var source =
          {
              url: "Home/DataHandler",
              datatype: "json",
              datafields: [{ name: "FirstName" }, { name: "LastName" }, { name: "Product" }, { name: "Price", type: "float" }, { name: "Quantity", type: "int" }, { name: "Total", type: "float" }]
          };

        var dataAdapter = new $.jqx.dataAdapter(source);

        $("#jqxgrid").jqxGrid(
          {
              source: dataAdapter,
              columns: [
                { text: 'First Name', dataField: 'FirstName', width: 100 },
                { text: 'Last Name', dataField: 'LastName', width: 100 },
                { text: 'Product', dataField: 'Product', width: 180 },
                { text: 'Quantity', dataField: 'Quantity', width: 80, cellsalign: 'right' },
                { text: 'Unit Price', dataField: 'Price', width: 90, cellsalign: 'right', cellsformat: 'c2' },
                { text: 'Total', dataField: 'Total', cellsalign: 'right', minwidth: 100, cellsformat: 'c2' }
              ]
          });
    });
</script>
<div id="jqxgrid"></div>

And here the Employee Model

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace JQWidgetGrids.Models
{
    public class EmployeesRepository
    {
        public static List<Employee> GetEmployees()
        {
            List<Employee> employees = new List<Employee>();

            string[] firstNames = new string[] { "Andrew", "Nancy", "Shelley", "Regina", "Yoshi", "Antoni", "Mayumi", "Ian", "Peter", "Lars", "Petra", "Martin", "Sven", "Elio", "Beate", "Cheryl", "Michael", "Guylene" };
            string[] lastNames = new string[] { "Fuller", "Davolio", "Burke", "Murphy", "Nagase", "Saavedra", "Ohno", "Devling", "Wilson", "Peterson", "Winkler", "Bein", "Petersen", "Rossi", "Vileid", "Saylor", "Bjorn", "Nodier" };
            string[] productNames = new string[] { "Black Tea", "Green Tea", "Caffe Espresso", "Doubleshot Espresso", "Caffe Latte", "White Chocolate Mocha", "Cramel Latte", "Caffe Americano", "Cappuccino", "Espresso Truffle", "Espresso con Panna", "Peppermint Mocha Twist" };
            string[] priceValues = new string[] { "2.25", "1.5", "3.0", "3.3", "4.5", "3.6", "3.8", "2.5", "5.0", "1.75", "3.25", "4.0" };
            Random random = new Random();

            for (var i = 0; i < 100; i++)
            {
                Employee employee = new Employee();

                int productindex = random.Next(productNames.Length);
                float price = float.Parse(priceValues[productindex]);
                int quantity = 1 + random.Next(10);
                employee.FirstName = firstNames[random.Next(firstNames.Length)];
                employee.LastName = firstNames[random.Next(lastNames.Length)];
                employee.Price = price;
                employee.Quantity = quantity;
                employee.Product = productNames[productindex];
                employees.Add(employee);
            }
            return employees;
        }
    }

    public class Employee
    {
        public int ID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Product { get; set; }
        public double Price { get; set; }
        public int Quantity { get; set; }
        public double Total
        {
            get
            {
                return this.Price * this.Quantity;
            }
        }
    }
}

Solution

  • Your seeing that screen because you calling your DataHandler() method directly (via a link or the browser address bar). That methods purpose is to return a JsonResult for use by your jqwidget plugin and you should not be navigating to it.

    Change the name of your DataHandler.cshtml view to Index.cshtml and then navigate to the Index() method of HomeController. That method will then return the view you have shown, which will in turn call you DataHandler() method to return the data to populate the grid.

    To prevent navigating directly to that method, you can decorate the DataHandler() method with a [AjaxOnly] only attribute. A typical example looks like

    [AttributeUsage(AttributeTargets.Method)]
    public class AjaxOnlyAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (!filterContext.HttpContext.Request.IsAjaxRequest())
            {
                filterContext.HttpContext.Response.StatusCode = 404;
                filterContext.Result = new HttpNotFoundResult();
            }
            else
            {
                base.OnActionExecuting(filterContext);
            }
        }
    }
    

    As a side note, your DataHandler() is not really required, and you can just pass the model in the initial request and save the extra overhead of making a 2nd call back to the server. Change the code in the Index() method to

    public ActionResult DataHandler()
    {
        List<Employee> model = EmployeesRepository.GetEmployees();
        return View(model );
    }
    

    then in the view, add

    @model IEnumerable<Employee>
    ...
    

    and then change the script to use the model you have passed to the view using the localdata data option

    var source = {
        datatype: "json",
        datafields: [{ name: "FirstName" }, { name: "LastName" }, { name: "Product" }, { name: "Price", type: "float" }, { name: "Quantity", type: "int" }, { name: "Total", type: "float" }]
        localdata: @Html.Raw(Json.Encode(Model))
    };