Возможно, у вас есть проблемы на стороне сервера. Не могли бы вы добавить свой вопрос с кодом действия DynamicGridData
, которое вы сейчас используете. Действие должно иметь filters
в качестве параметра.
Некоторые части вашего текущего кода совершенно неверны. Например, jqGrid
- это плагин jQuery. Таким образом, методы jQuery будут расширены основным jqGrid
методом, который вы используете как jQuery("#list").jqGrid(...);
. Поэтому после инициализации jqGrid jQuery("#list").jqGrid
станет функцией. В вашем коде (последнее утверждение) вы перезаписываете метод jQuery("#list").jqGrid
объектом { search: { ... } }
. Вместо этого вы должны
jQuery.extend(jQuery.jgrid.search, {
odata : ['equal', 'not equal','contains']
});
как, например, здесь описано, как перезаписать значение emptyrecords
по умолчанию. Вам не нужно включать значения, которые уже совпадают, в настройках jqGrid по умолчанию.
Более того, если вы используете searchoptions: { sopt: ['eq', 'ne', 'cn']}
во всех доступных для поиска столбцах, вам не нужно вносить изменения.
В тексте вашего вопроса вы не объяснили, что вы хотите сделать. Ваш текущий код таков, что вы используете фильтр Message
, равный true
при начальной загрузке сетки. Странно, что в сетке нет столбца с именем Message
. Если вы хотите просто отправить дополнительную информацию на сервер, вам лучше использовать параметр postData
:
postData: {Message:true}
Я продолжаю рекомендовать вам удалить мусор из определения jqGrid, например, imgpath
и multipleSearch
параметров jqGrid и sortable: true, search: true, sorttype: 'text', autoFit: true, stype:'text', align: 'left'
, которые либо неизвестны, либо заданы по умолчанию.
ОБНОВЛЕНО : исходный код демонстрационной версии Phil Haack очень старый и использует LINQ to SQL. Как я писал ранее (см. здесь ) Entity Framework (EF) позволяет использовать сортировку, разбиение на страницы и фильтрацию / поиск без каких-либо надстроек, таких как LINQ Dynamic Query Library в форме System.Linq.Dynamic
. Итак, я сделал вам демо, которое является модификацией демо Фила Хаака для EF.
Поскольку вы используете старую версию Visual Studio (VS2008 с ASP.NET MVC 2.0), я сделал демонстрацию также в VS2008.
Вы можете загрузить мою демоверсию VS2008 с здесь и демоверсией VS2010 здесь .
В коде, который я показываю (помимо использования расширенного поиска и поиска на панели инструментов в ASP.NET MVC 2.0), как вернуть информацию об исключении из ASP.NET MVC в формате JSON и как перехватить информацию с помощью loadError и отобразите соответствующее сообщение об ошибке.
Чтобы построить оператор Где из ObjectQuery представленного объекта EF, я определил следующий вспомогательный класс:
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;
}
}
В примере я использую только два типа данных integer
(Edm.Int32
) и string
(Edm.String
). Вы можете легко расширить пример, чтобы использовать больше типов на основе значения propertyInfo.PropertyType.FullName
, как указано выше.
Действие контроллера, предоставляющее данные в jqGrid, будет довольно простым:
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()
});
}
Чтобы отправить информацию об исключении в jqGrid в форме JSON, я заменил стандартный атрибут [HandleError]
контроллера (HomeController
) на [HandleJsonException]
, который я определил следующим образом:
// 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;
}
}
}
На стороне клиента я использовал следующий код JavaScript:
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(); }
});
В результате, если на панели инструментов поиска вводится какой-либо нечисловой текст (например, «ttt»), получается исключение кода действия контроллера (в Int32.Parse(rule.data)
). На стороне клиента вы увидите следующее сообщение:
Я отправляю с контроллера в jqgrid информацию обо всех внутренних исключениях. Так, например, ошибка подключения к серверу SQL будет выглядеть как
В реальном мире проверяется ввод данных пользователем и выдается исключение с сообщением об ошибке, ориентированным на приложение. Я использовал в демо, в частности, нет такого рода проверки, чтобы показать, что все виды исключений будут кэшироваться и отображаться jqGrid.
ОБНОВЛЕНО 2 : В ответе вы найдете модифицированную демоверсию VS2010 (которую можно загрузить с здесь ), демонстрирующую использование jQuery UI Autocomplete. Другой ответ Расширьте код, чтобы экспортировать сетку, содержащуюся в формате Excel.