Я работаю над своим первым приложением ASP.NET MVC 3 и использую jqGrid для отображения / фильтрации / сортировки табличных данных.В целом, это сработало очень хорошо для меня.Одна из неприятных проблем, с которыми я столкнулся (о чем упоминали и пользователи), заключается в том, что выпадающие списки фильтров не зависят друг от друга. Я имею в виду, что они не реагируют и не перезагружаются в зависимости от выбора других.Позвольте привести пример.У меня есть таблица, в которой отображаются следующие данные столбца:
Category SubCategory RecipeName RecipeAuthor
Для раскрывающегося списка столбца Категория я получаю список категорий десертов (например, «Пирог», «Печенье», «Пирог» и т. Д.).) и я предполагаю, что эта категория десертов будет вести другие колонки.Я бы хотел получить, скажем, только подкатегории cookie, если пользователь выбрал категорию «Cookie», потому что фильтрация имеет смысл только в этом случае - сетка будет корректно реагировать, например, если я фильтрую по категории «Cookie» и выбираю «Лимонные шахматы»"(круговая подкатегория), тогда он ничего не отобразит (так как мы не создаем лимонное печенье с шахматами (, но, возможно, нам следует ) - но это немного неуклюжий интерфейс. Лучше получать только подкатегорииЯ думаю, что это связано с отфильтрованной категорией.
Если пользователь не выбирает категорию, представляется разумным отобразить все данные, и, таким образом, в раскрывающихся списках подкатегории, получателя и рецепта отобразятся всевозможные варианты.
В моем коде jqGrid я определяю мои выпадающие списки следующим образом:
{ name: 'CategoryID', index: 'CategoryID', width: 200,
editable: true, align: 'left', edittype: 'select', stype: 'select',
editoptions: {
dataUrl: '@Url.Action("AvailableDessertCategories", "Dessert")',
buildSelect: createSelectList
},
searchoptions: {
dataUrl: '@Url.Action("AvailableDessertCategories", "Dessert")',
buildSelect: createSelectList,
sopt: ['eq']
}
},
(для каждого из этих столбцов есть похожий фрагмент кода)
И createSelectList определяется как:
createSelectList = function (data) {
var response, s = '<select>', i, l, ri;
if (typeof (data) === "string") {
//var leng = data.length - 1;
response = jQuery.parseJSON(data);
}
else {
response = jQuery.parseJSON(data.responseText);
s += '<option value="">Select...</option>';
}
if (response && response.length) {
for (i = 0, l = response.length; i < l; i += 1) {
ri = response[i];
s += '<option value="' + ri + '">' + ri + '</option>';
}
}
return s + '</select>';
}
, и мое действие, которое возвращает список для заполнения раскрывающегося списка, выглядит следующим образом:
public JsonResult AvailableDessertCategories()
{
var context = new DessertEntities();
var dbquery = context.DessertCategories.AsQueryable();
List<string> all = dbquery.Select(m => m.CategoryID).Where(m => m != null).Distinct().ToList();
return Json(all, JsonRequestBehavior.AllowGet);
}
На другой странице я делаю что-то вроде того, что хочу здесь для двух выпадающих списков.Представление выглядит следующим образом:
@Html.DropDownListFor(model => model.FlavorID, new SelectList(Model.IceCreamFlavors, "ID", "Name"), "-- Select Ice Cream --", new { @id = "icecreamselector" })
@Html.DropDownListFor(model => model.RecipeID, Enumerable.Empty<SelectListItem>(), "-- Select Recipe --", new { @id = "recipeselector" })
и использует некоторый jQuery для заполнения раскрывающегося списка рецептов следующим образом:
$('#icecreamselector').change(function () {
var selectedFlavorID = $(this).val();
if (selectedFlavorID != null) {
$.getJSON('@Url.Action("RecipesForFlavor")', { flavorID: selectedFlavorID }, function (recipes) {
var recipeSelect = $('#recipeselector');
recipeSelect.empty();
recipeSelect.append($('<option/>', { value: 0, text: 'No Recipe' }));
$.each(recipes, function (index, recipe) {
recipeSelect.append($('<option/>', {
value: recipe.ID,
text: recipe.Name
}));
});
var theVal = $("#hiddenrecipeid").val();
if (theVal != null && theVal != "") {
$('#recipeselector').val(theVal);
}
});
}
});
И передает идентификатор вкуса мороженого в это действие RecipesForFlavor и фильтрывниз рецепты соответственно.Я думаю, что я не могу сделать скачок здесь, как сделать то же самое с выпадающими списками сетки.Две части, в которых я не уверен, - это как реагировать на тот факт, что пользователь выбрал что-то в раскрывающемся списке «Категория» (или что оно было установлено автоматически), а затем как получить идентификатор из этого выбора.Я думаю, что код извлечения (действие контроллера) - это то же самое, что я использовал в другом месте, но я думаю, что другой вопрос, который нужно решить, - это затем установить эти значения извлечения в выпадающем списке Подкатегории (и двух других тоже).Я предполагаю, что у других есть подобные вещи.Любое руководство было бы очень полезно.
A Решение:
Чтобы решить проблему каскадного фильтра, я взглянул на примеры Олега и немного почерпнул изих.Возможно, это не идеальное решение, но, похоже, оно мне подходит.По сути, я добавил dataEvents
раздел (извините, я действительно не очень-то люблю программист javascript - я подозреваю, что для этого есть какой-то термин) к searchoptions
, который выполняет следующее:
searchoptions: {
dataUrl: '@Url.Action("AvailableDessertCategories", "Dessert")',
buildSelect: createSelectList,
sopt: ['eq'],
dataEvents: [
{
type: 'change',
fn: function (e) {
// grab the category and then update recipes based on it
var selectedCategory = $(e.target).val();
if (selectedCategory !== '') {
$.getJSON('@Url.Action("RecipeNamesForCategory", "Dessert")', { category: selectedCategory }, function (recipes) {
var row = $(e.target).closest('tr.ui-search-toolbar');
var recipeSelect = $("#gs_RecipeName", row[0]);
recipeSelect.empty();
recipeSelect.append('<option value="">Select...</option>');
$.each(recipes, function (index, recipe) {
recipeSelect.append($('<option/>', {
value: recipe,
text: recipe
}));
});
});
}
}
}
]
}
Это очищает выпадающий список рецептов (#gs_RecipeName
) и затем использует данные JSON, возвращенные из моего действия RecipeNamesForCategory
на моем контроллере Dessert
для данной категории.Он добавляет пустую запись «Выбрать ...», чтобы разрешить отображение всех рецептов, а не всегда выполнять фильтрацию по одному рецепту, а затем перебирает имена рецептов и создает записи для них.
Примечание:
Я подозреваю, однако, что это можно улучшить.Например, у меня есть функция createSelectList
, которая является общей для четырех различных сеток, которые есть на сайте, и, вероятно, я могу сделать что-то подобное и для этого.Кажется немного неуклюжим повторять этот код для каждой из четырех сеток.
Редактировать:
Я закончил тем, что убрал проверку if (selectedCategory !== '')
из кода и изменил действие, которое извлекало имена моих рецептов, чтобы оно правильно делало, отправлялась ли ему категория или пустая строка. В противном случае, если я очистил фильтр категорий (выбрав опцию «Выбрать ...»), селектор имени рецепта не будет повторно заполнен всеми именами рецептов.