Каскадные или связанные фильтры на jqGrid - PullRequest
0 голосов
/ 10 сентября 2011

Я работаю над своим первым приложением 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 !== '') из кода и изменил действие, которое извлекало имена моих рецептов, чтобы оно правильно делало, отправлялась ли ему категория или пустая строка. В противном случае, если я очистил фильтр категорий (выбрав опцию «Выбрать ...»), селектор имени рецепта не будет повторно заполнен всеми именами рецептов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...