Implementation of searching in jqgrid in ASP.NET MVC 2.0

asp.net-mvc-2 entity-framework jqgrid linq-to-entities search

Question

This is the code I have so far for utilizing the single column search in the jqgrid using MVC 2 in.NET (VS 2008), however I need an example to compare it to or a hint as to what I am missing.

jQuery("#list").jqGrid({
    url: '/Home/DynamicGridData/',
    datatype: 'json',
    mtype: 'POST',
    search: true,
    filters: {
        "groupOp":"AND",
        "rules": [
            {"field":"Message","op":"eq","data":"True"}
        ]
    },
    multipleSearch: false,
    colNames: [ 'column1', 'column2'],
    colModel: [
        { name: 'column1', index: 'column1', sortable: true, search: true,
          sorttype: 'text', autoFit: true,stype:'text',
          searchoptions: { sopt: ['eq', 'ne', 'cn']} },
        { name: 'column2', index: 'column2', sortable: true,search: false,
          sorttype: 'text', align: 'left', autoFit: true}],
    pager: jQuery('#pager'),
    rowNum: 10,
    rowList: [10, 60, 100],
    scroll: true,
    sortname: 'column2',
    sortorder: 'asc',
    gridview: true,
    autowidth: true,
    rownumbers: true,
    viewrecords: true,
    imgpath: '/scripts/themes/basic/images',
    caption: 'my data grid'
});

jQuery("#list").jqGrid('navGrid', '#pager', {add: false, edit: false, del: false},
                       {}, {}, {}, { multipleSearch: true, overlay: false });
//jQuery("#list").jqGrid('filterToolbar', {stringResult:true, searchOnEnter:true});
jQuery("#list").jqGrid('navButtonAdd', '#pager',
                      { caption: "Finding", title: "Toggle Search Bar",
                        buttonicon: 'ui-icon-pin-s',
                        onClickButton: function() { $("#list")[0].toggleToolbar() }
                      });

jQuery("#list").jqGrid = {
    search : {
        caption: "Search...",
        Find: "Find",
        Reset: "Reset",
        odata : ['equal', 'not equal','contains'],
        groupOps: [ { op: "AND", text: "all" }, { op: "OR", text: "any" } ],
        matchText: " match",
        rulesText: " rules"
    }
}                              

});

two items Even though I have the search window open and only have the column 1 choice, neither paging nor search are working. When I click Find, it seems as if the grid is loaded, but in reality nothing matches the value that I put into the text field.

As you can see, I tried using the serach parameter, but it didn't work. I appreciate your assistance and thank you again.

//public ActionResult DynamicGridData(string sidx, string sord, int page, int rows,bool search, string fieldname,string fieldvalue)
public ActionResult DynamicGridData(string sidx, string sord, int page, int rows)
{
    var context = new  AlertsManagementDataContext();
    int pageIndex = Convert.ToInt32(page) - 1;
    int pageSize = rows;
    int totalRecords = context.Alerts.Count();
    int totalPages = (int)Math.Ceiling((float)totalRecords / (float)pageSize);

    IQueryable<Alert> alerts = null;
    try
    {
       //if (!search)
       //{
           alerts = context.Alerts.
           OrderBy(sidx + " " + sord).
           Skip(pageIndex * pageSize).
           Take(pageSize);
       //}
       //else
       //{
       //    alerts = context.Alerts.Where (fieldname +"='"+ fieldvalue +"'").
       //    Skip(pageIndex * pageSize).
       //    Take(pageSize);
       //}
    }
    catch (ParseException ex)
    {
        Response.Write(ex.Position + "  " + ex.Message + "  " + ex.Data.ToString());
    }

    //var alerts =
    //    from a in context.Alerts
    //    orderby sidx ascending
    //    select a;

    var jsonData = new {
        total = totalPages,
        page = page,
        records = totalRecords,

        rows = (
          from alert in alerts

          select new {
            id = alert.AlertId,
            cell = new string[] {
                "<a href=Home/Edit/"+alert.AlertId +">Edit</a> " +"|"+
                    "<a href=Home/Details/"+alert.AlertId +">Detail</a> ",
                alert.AlertId.ToString() ,
                alert.Policy.Name ,
                alert.PolicyRule ,
                alert.AlertStatus.Status ,
                alert.Code.ToString() ,
                alert.Message ,
                alert.Category.Name}
        }).ToArray()
    };

    return Json(jsonData);
}
1
25
4/2/2011 5:32:34 PM

Accepted Answer

You most likely have a server-side issue. Could you please provide the code for in your inquiryDynamicGridData which you now practice. The activity need to havefilters as the criterion.

Your existing code contains several blatantly incorrect elements. For instancejqGrid is a plugin for jQuery. Therefore, the jQuery methods will be expanded with the primaryjqGrid a technique you use asjQuery("#list").jqGrid(...); Therefore, when jqGrid has been initializedjQuery("#list").jqGrid will serve a purpose. You replace the last statement in your code withjQuery("#list").jqGrid a process using the object{ search: { ... } } Instead, what you need to do is

jQuery.extend(jQuery.jgrid.search, {
    odata : ['equal', 'not equal','contains']
});

like, for instance, here, how to replace theemptyrecords default setting. The values that are the same in the default jqGrid settings don't need to be added.

In addition, if you utilizesearchoptions: { sopt: ['eq', 'ne', 'cn']} You don't have to make the adjustment for any of the searchable columns.

You don't explicitly state what you wish to accomplish in the body of your query. The code you currently have allows you to utilize the filter.Message like totrue when the grid first loads. It's odd that there isn't a column with the name in it.Message throughout the grid. If you just wish to give the server a little amount of extra information, you should usepostData parameter:

postData: {Message:true}

I still urge you to eliminate unnecessary elements from the jqGrid specification, such asimgpath and multipleSearch components of jqGrid andsortable: true, search: true, sorttype: 'text', autoFit: true, stype:'text', align: 'left' which are either default or unknown.

UPDATED: The extremely old original code for demo by Phil Haack uses LINQ to SQL. Entity Framework (EF), as I previously said (see here), enables the usage of sorting, paging, and filtering/searching without the need for AddOns like LINQ Dynamic Query Library in forms.System.Linq.Dynamic . So I modified the demo by Phil Haack to EF and created the sample for you.

I created the sample on VS2008 as well since you're using an outdated version of Visual Studio (VS2008 with ASP.NET MVC 2.0).

You may get my VS2008 and VS2010 demos at here and here, respectively.

In the code, I demonstrate how to return exception information from ASP.NET MVC in JSON format, how to catch the information using the loadError function, and how to display the appropriate error message in addition to using Advanced Searching and Toolbar Searching in ASP.NET MVC 2.0.

I define the following helper class to create the Where statement from the ObjectQuery represented EF object:

public class Filters {
    public enum GroupOp {
        AND,
        OR
    }
    public enum Operations {
        eq, // "equal"
        ne, // "not equal"
        lt, // "less"
        le, // "less or equal"
        gt, // "greater"
        ge, // "greater or equal"
        bw, // "begins with"
        bn, // "does not begin with"
        //in, // "in"
        //ni, // "not in"
        ew, // "ends with"
        en, // "does not end with"
        cn, // "contains"
        nc  // "does not contain"
    }
    public class Rule {
        public string field { get; set; }
        public Operations op { get; set; }
        public string data { get; set; }
    }

    public GroupOp groupOp { get; set; }
    public List<Rule> rules { get; set; }
    private static readonly string[] FormatMapping = {
        "(it.{0} = @p{1})",                 // "eq" - equal
        "(it.{0} <> @p{1})",                // "ne" - not equal
        "(it.{0} < @p{1})",                 // "lt" - less than
        "(it.{0} <= @p{1})",                // "le" - less than or equal to
        "(it.{0} > @p{1})",                 // "gt" - greater than
        "(it.{0} >= @p{1})",                // "ge" - greater than or equal to
        "(it.{0} LIKE (@p{1}+'%'))",        // "bw" - begins with
        "(it.{0} NOT LIKE (@p{1}+'%'))",    // "bn" - does not begin with
        "(it.{0} LIKE ('%'+@p{1}))",        // "ew" - ends with
        "(it.{0} NOT LIKE ('%'+@p{1}))",    // "en" - does not end with
        "(it.{0} LIKE ('%'+@p{1}+'%'))",    // "cn" - contains
        "(it.{0} NOT LIKE ('%'+@p{1}+'%'))" //" nc" - does not contain
    };
    internal ObjectQuery<T> FilterObjectSet<T> (ObjectQuery<T> inputQuery) where T : class {
        if (rules.Count <= 0)
            return inputQuery;

        var sb = new StringBuilder();
        var objParams = new List<ObjectParameter>(rules.Count);

        foreach (Rule rule in rules) {
            PropertyInfo propertyInfo = typeof (T).GetProperty (rule.field);
            if (propertyInfo == null)
                continue; // skip wrong entries

            if (sb.Length != 0)
                sb.Append(groupOp);

            var iParam = objParams.Count;
            sb.AppendFormat(FormatMapping[(int)rule.op], rule.field, iParam);

            // TODO: Extend to other data types
            objParams.Add(String.Compare(propertyInfo.PropertyType.FullName,
                                         "System.Int32", StringComparison.Ordinal) == 0
                              ? new ObjectParameter("p" + iParam, Int32.Parse(rule.data))
                              : new ObjectParameter("p" + iParam, rule.data));
        }

        ObjectQuery<T> filteredQuery = inputQuery.Where (sb.ToString ());
        foreach (var objParam in objParams)
            filteredQuery.Parameters.Add (objParam);

        return filteredQuery;
    }
}

I just use two datatypes in the example.integer (Edm.Int32 ) andstring (Edm.String It is simple to extend the example to incorporate new types based on the ones mentioned previously.propertyInfo.PropertyType.FullName value.

The controller action that feeds data to the jqGrid will be rather straightforward:

public JsonResult DynamicGridData(string sidx, string sord, int page, int rows, bool _search, string filters)
{

    var context = new HaackOverflowEntities();
    var serializer = new JavaScriptSerializer();
    Filters f = (!_search || string.IsNullOrEmpty (filters)) ? null : serializer.Deserialize<Filters> (filters);
    ObjectQuery<Question> filteredQuery =
        (f == null ? context.Questions : f.FilterObjectSet (context.Questions));
    filteredQuery.MergeOption = MergeOption.NoTracking; // we don't want to update the data
    var totalRecords = filteredQuery.Count();

    var pagedQuery = filteredQuery.Skip ("it." + sidx + " " + sord, "@skip",
                                        new ObjectParameter ("skip", (page - 1) * rows))
                                 .Top ("@limit", new ObjectParameter ("limit", rows));
    // to be able to use ToString() below which is NOT exist in the LINQ to Entity
    var queryDetails = (from item in pagedQuery
                        select new { item.Id, item.Votes, item.Title }).ToList();

    return Json(new {
                    total = (totalRecords + rows - 1) / rows,
                    page,
                    records = totalRecords,
                    rows = (from item in queryDetails
                            select new[] {
                                item.Id.ToString(),
                                item.Votes.ToString(),
                                item.Title
                            }).ToList()
                });
}

I updated the default JSON format with JSON to transmit the exception information to the jqGrid.[HandleError] a controller attribute (HomeController ) to the[HandleJsonException] which I characterized as being:

// to send exceptions as json we define [HandleJsonException] attribute
public class ExceptionInformation {
    public string Message { get; set; }
    public string Source { get; set; }
    public string StackTrace { get; set; }
}
public class HandleJsonExceptionAttribute : ActionFilterAttribute {
    // next class example are modification of the example from
    // the http://www.dotnetcurry.com/ShowArticle.aspx?ID=496
    public override void OnActionExecuted(ActionExecutedContext filterContext) {
        if (filterContext.HttpContext.Request.IsAjaxRequest() && filterContext.Exception != null) {
            filterContext.HttpContext.Response.StatusCode =
                (int)System.Net.HttpStatusCode.InternalServerError;

            var exInfo = new List<ExceptionInformation>();
            for (Exception ex = filterContext.Exception; ex != null; ex = ex.InnerException) {
                PropertyInfo propertyInfo = ex.GetType().GetProperty ("ErrorCode");
                exInfo.Add(new ExceptionInformation() {
                    Message = ex.Message,
                    Source = ex.Source,
                    StackTrace = ex.StackTrace
                });
            }
            filterContext.Result = new JsonResult() {Data=exInfo};
            filterContext.ExceptionHandled = true;
        }
    }
}

I used the following JavaScript code on the client side:

var myGrid = $('#list'),
    decodeErrorMessage = function(jqXHR, textStatus, errorThrown) {
        var html, errorInfo, i, errorText = textStatus + '\n' + errorThrown;
        if (jqXHR.responseText.charAt(0) === '[') {
            try {
                errorInfo = $.parseJSON(jqXHR.responseText);
                errorText = "";
                for (i=0; i<errorInfo.length; i++) {
                   if (errorText.length !== 0) {
                       errorText += "<hr/>";
                   }
                   errorText += errorInfo[i].Source + ": " + errorInfo[i].Message;
                }
            }
            catch (e) { }
        } else {
            html = /<body.*?>([\s\S]*)<\/body>/.exec(jqXHR.responseText);
            if (html !== null && html.length > 1) {
                errorText = html[1];
            }
        }
        return errorText;
    };
myGrid.jqGrid({
    url: '<%= Url.Action("DynamicGridData") %>',
    datatype: 'json',
    mtype: 'POST',
    colNames: ['Id', 'Votes', 'Title'],
    colModel: [
        { name: 'Id', index: 'Id', key: true, width: 40,
            searchoptions: { sopt: ['eq', 'ne', 'lt', 'le', 'gt', 'ge'] }
        },
        { name: 'Votes', index: 'Votes', width: 40,
            searchoptions: { sopt: ['eq', 'ne', 'lt', 'le', 'gt', 'ge'] }
        },
        { name: 'Title', index: 'Title', width: 400,
            searchoptions: { sopt: ['cn', 'nc', 'bw', 'bn', 'eq', 'ne', 'ew', 'en', 'lt', 'le', 'gt', 'ge'] }
        }
    ],
    pager: '#pager',
    rowNum: 10,
    rowList: [5, 10, 20, 50],
    sortname: 'Id',
    sortorder: 'desc',
    rownumbers: true,
    viewrecords: true,
    altRows: true,
    altclass: 'myAltRowClass',
    height: '100%',
    jsonReader: { cell: "" },
    caption: 'My first grid',
    loadError: function(jqXHR, textStatus, errorThrown) {
        // remove error div if exist
        $('#' + this.id + '_err').remove();
        // insert div with the error description before the grid
        myGrid.closest('div.ui-jqgrid').before(
            '<div id="' + this.id + '_err" style="max-width:'+this.style.width+
            ';"><div class="ui-state-error ui-corner-all" style="padding:0.7em;float:left;"><span class="ui-icon ui-icon-alert" style="float:left; margin-right: .3em;"></span><span style="clear:left">' +
                        decodeErrorMessage(jqXHR, textStatus, errorThrown) + '</span></div><div style="clear:left"/></div>')
    },
    loadComplete: function() {
        // remove error div if exist
        $('#' + this.id + '_err').remove();
    }
});
myGrid.jqGrid('navGrid', '#pager', { add: false, edit: false, del: false },
              {}, {}, {}, { multipleSearch: true, overlay: false });
myGrid.jqGrid('filterToolbar', { stringResult: true, searchOnEnter: true, defaultSearch: 'cn' });
myGrid.jqGrid('navButtonAdd', '#pager',
            { caption: "Filter", title: "Toggle Searching Toolbar",
                buttonicon: 'ui-icon-pin-s',
                onClickButton: function() { myGrid[0].toggleToolbar(); }
            });

As a consequence, if one enters any non-numeric text in the search toolbar, such as "ttt," they will get an exception and the controller action code (inInt32.Parse(rule.data) One will notice the following message on the client side:

enter image description here

I provide all internal exception information from the controller to the jqgrid. As an example, the SQL server connection problem will appear as

enter image description here

In the actual world, users' input is verified before an exception is raised and an application-oriented error message is shown. I specifically avoided using this form of validation in the sample to demonstrate how jqGrid would save and display any kind of error.

REVISED 2: The improved VS2010 demo that shows how to use jQuery UI Autocomplete can be downloaded from here. Another response extends the code further to export the grid's contents in Excel format.

26
5/23/2017 12:26:04 PM



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow