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()
неверно, потому что
Вы не можете связать
<select multiple>
в коллекцию сложных объектов, которые вашиClasses
свойство - модель должна быть коллекцией типов значений, ивы не можете использовать одно и то же имя для свойства, к которому вы привязываете
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>