Как добавить несколько экземпляров класса T в свойство List of T при создании экземпляра другого класса ASP.NET Core
Имеется класс Skill и класс Course
public class Course
{
public int Id { get; set; }
public string? Name { get; set; }
public string? Description { get; set; }
public List<Skill>? CourseSkills { get; set; }
[Required(ErrorMessage = "You must be authorized!")]
public string CreatorUserName { get; set; }
}
public class Skill
{
public string Name { get; set; }
public string? Description { get; set; }
public List<Course>? Courses { get; set; }
public int Id { get; set; }
}
public class CourseViewModel
{
public List<SelectListItem>? SkillSelectList { get; set; }
public int SelectedSkillId { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public string? Description { get; set; }
[Required(ErrorMessage = "You must be authorized!")]
public string CreatorUserName { get; set; }
}
При создании экземпляра класса Course через стандартный ASP.NET CRUD интерфейс необходимо как-то добавлять несколько уже существующих экземпляров класса Skill из списка внутри select-a
Как я себе это представляю:
(input) [_ введите Имя для Course _]
(select) [_ выберите Skill _] (button) [_ добавить Skill в Course _]
(button) [_ создать Course _]
При нажатии на (button) [_ добавить Skill в Course _] ниже текущего select-a появляется еще один select и button, где можно было бы так же выбрать еще Skill
И при нажатии (button) [_ создать Course _] в метод Create контроллера CourseController передавался бы List_of_Skills или Array_of_Skills (+ прочие свойства, типа Name и тд)
Либо просто в одном select-e выбирать несколько и передавать их в контроллер в виде List или Array
Пока что разобрался только с добавлением одного Skill в Course :
@model Prog.Models.ViewModels.CourseViewModel
@{
ViewData["Title"] = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Create course</h1>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group mb-3">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="mb-3 form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Description" class="control-label"></label>
<input asp-for="Description" class="mb-3 form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CreatorUserName" class="control-label"></label>
<input asp-for="CreatorUserName" class="mb-3 form-control" value="@User.Identity?.Name" readonly="true"/>
</div>
<div class="form-group mb-3">
<select class="form-select" asp-items="Model.SkillSelectList" asp-for="SelectedSkillId">
<option value="0">-- Please Select a Skill --</option>
</select>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-outline-primary" />
</div>
</form>
</div>
</div>
Идеи, варианты?
Ответы (2 шт):
Модель Course
public class Course
{
public int Id { get; set; }
public string? Name { get; set; }
public string? Description { get; set; }
public int SkillId { get; set; }
[ForeignKey("SkillId")]
public virtual Skill? Skill { get; set; }
[Required(ErrorMessage = "You must be authorized!")]
public string CreatorUserName { get; set; }
}
Фрагмент кода метода Create для Контроллера Course (для архитектуры MVC)
public IActionResult Create()
{
// извлечение скиллов из базы данных и конвертация в объект специального типа
IEnumerable<SelectListItem> SkillsDropdown = _db.Skills.Select(i=> new SelectListItem { Text=i.Name, Value=i.Id.ToString()});
// создание ViewBag для передачи в представление
ViewBag.SkillsDropDown= SkillsDropDown;
Course course = new();
return View(course)
}
View
@model Course
<form method="post"
.....
// блок с выбором скилов из выпадающего меню
<div>
<select asp-for="SkillId" asp-items="@ViewBag.SkillsDropDown"
</div>
//передача данных в метод пост из полей ввода
<div>
<input type="submit" value="Create"
</div>
Также в контроллере нужно будет создать метод Create типа POST, для записи в базу данных нового Course.
ViewBag это костыль, и правильнее создавать ViewModel для работы с данными о Course.
Подробный пример решения, для вашего случая в курсе по ссылке.
Если правильно понял вы хотите передать в модель CourseViewModel несколько Skill.
Тогда в классе CourseViewModel заменим свойство
public int SkillId { get; set; }
на свойство
public List<int> SkillIds { get; set; }
так как нам нужен список, а не один элемент.
Далее, чтобы с представления получать список значений, к тегу select добавьте атрибут multiple.
В общем должно получиться так:
<select multiple class="form-select" asp-items="Model.SkillSelectList" asp-for="SkillIds">
</select>
на самом представлении это будет выглядеть так: 
Да, стандартный мультиселект выглядит не очень, к этому вернёмся позже.
Теперь зажимаем CTRL и выбираем нужные элементы (в стандартном только так).
Далее нажав Create в контролере мы увидим выбранные элементы, для примера выбрал 1 и 3: 
Теперь изменим стандартный мультиселект. Если погуглить есть много вариантов/стилей для мультиселекта, мне понравился отсюда https://github.com/snapappointments/bootstrap-select. И в итоге будет выглядеть так, и через CTRL уже выбирать не надо
По ссылке описана установка, но если коротко:
- через
nugetустановитьbootstrap-select - в файле
_Layout:- в
headдобавить<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap-select.min.css"> - после
jquery.jsиbootstrap.jsдобавить<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap-select.min.js"></script>
- в
- к селекту добавить класс
selectpickerблагодоря этому преобразование в селект что на последнем скрине происходит автоматически
