JQuery Multiselect - группировка из базы данных

Я использую плагин множественного выбора jquery [ https://github.com/davidstutz/bootstrap-multiselect] и динамически связываю его со значениями базы данных.

HTML

@Html.ListBoxFor(m => m.Classes, new SelectList(Model.Classes, "Value", "Text"), new { @id = "classList" })

SCRIPT

$('#classList').multiselect({ enableClickableOptGroups: true });

Модель в представлении является моделью представления и содержит свойство для SelectList

public class SearchControlViewModel 
{
    ....
    public SelectList Classes { get; set; }
}

и код в контроллере

SearchControlViewModel  model = new SearchControlViewModel()
{
    ....
    Classes = new SelectList(repClass.GetClassesByYear(23), "classID", "classname")
};
return View(model);

Это работает как шарм, за исключением одного - я хочу добавить группирование / заголовок группы, как <optgroup> делает. Как я могу это сделать?

GetClassesByYear() метод, используемый для генерации SelectList возвращает объект, содержащий свойства int classID, string classname а также string grade и я хочу иметь возможность сгруппировать варианты по grade,

1 ответ

Решение

Группы опций не поддерживаются в MVC-4, и вам потребуется обновить его до MVC-5, чтобы использовать готовые функции. Если вы выполните обновление, обратитесь к разделу "Создание списка выбора с группами OptGroup" для примеров, использующих оба SelectList конструктор, и путем генерации IEnumerable<SelectListItem>

Без обновления вы можете передать в представление модель, представляющую ваши группы и их параметры, и использовать некоторый javascript/jquery для генерации элементов. Начните с создания дополнительных моделей представлений

public class OptionGroupVM
{
    public string GroupName { get; set; }
    public IEnumerable<OptionVM> Options { get; set; }
}
public class OptionVM
{
    public string Value { get; set; }
    public string Text { get; set; }
    public bool IsSelected { get; set; } // Only applicable if your not binding to a model property
}

Затем измените модель основного вида, включив в нее следующее

public class SearchControlViewModel 
{
    ....
    public IEnumerable<int> SelectedClasses { get; set; }
    public IEnumerable<OptionGroupVM> ClassOptions { get; set; }
}

Обратите внимание, что ваша текущая модель и использование ListBoxFor() неверно, потому что

  1. Вы не можете связать <select multiple> в коллекцию сложных объектов, которые ваши Classes свойство - модель должна быть коллекцией типов значений, и

  2. вы не можете использовать одно и то же имя для свойства, к которому вы привязываете SelectList - будет ли конфликт, если я укажу имя viewBag равным имени свойства модели в @Html.DropDownListFor для более подробной информации

В контроллере

var data = repClass.GetClassesByYear(23);
var groupedOptions = data.GroupBy(x => x.grade).Select(x => new OptionGroupVM()
{
    GroupName = x.Key.ToString(),
    Options = x.Select(y => new OptionVM()
    {
        Value = y.classId.ToString(),
        Text = y.classcame,
    })
});
SearchControlViewModel model = new SearchControlViewModel()
{
    ....
    SelectedClasses = ...., // the values of the options that will be pre-selected
    ClassOptions = groupedOptions
};
return View(model);

И в представлении использовать

@Html.ListBoxFor(m => SelectedClasses, Enumerable.Empty<SelectListItem>(), new { id = "classList" })

который первоначально будет генерировать <select> без каких-либо вариантов. Затем используйте следующий скрипт для генерации опций

<script type="text/javascript">
    // Get data
    var listBox = $('#classList');
    var selected = @Html.Raw(Json.Encode(Model.SelectedClasses));
    var groups = @Html.Raw(Json.Encode(Model.ClassOptions));

    // Generate options
    createGroupedOptions(listBox, selected, groups);
    // Attach plug-in
    listBox.multiselect({ enableClickableOptGroups: true });

    // This function could be in an external js file
    function createGroupedOptions(element, selected, groups) {
        for (var i = 0; i < groups.length; i++) {
            var group = groups[i];
            var groupElement = $('<optgroup></optgroup>').attr('label', group.GroupName);
            for(var j = 0; j < group.Options.length; j++) {
                var option = group.Options[j];
                var optionElement = $('<option></option>').val(option.Value).text(option.Text);
                if (selected) {
                    if (selected.toString().indexOf(option.Value) >= 0) {
                        optionElement.attr('selected', 'selected')
                    }
                } else {
                    if (option.IsSelected) {
                        optionElement.attr('selected', 'selected')
                    }
                }

                $(groupElement).append(optionElement);
            }
            $(element).append(groupElement);
        }
    }
</script>
Другие вопросы по тегам