I try make a library Sistem where in category to book has a relation many to many i need put in my book edit view a partial view frow the entity, could someone help-me?
my edit view:
@model MVC_Library.Models.Book
@{
ViewData["Title"] = "Edit";
BookCategory teste = ViewBag.testeview;
}
<h1>Edit</h1>
<h4>Book</h4>
<hr />
<div >
<div >
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" ></div>
<input type="hidden" asp-for="BookId" />
<div >
<label asp-for="Title" ></label>
<input asp-for="Title" />
<span asp-validation-for="Title" ></span>
</div>
<div >
<label asp-for="Author" ></label>
<input asp-for="Author" />
<span asp-validation-for="Author" ></span>
</div>
<div >
<label asp-for="PublishDate" ></label>
<input asp-for="PublishDate" />
<span asp-validation-for="PublishDate" ></span>
</div>
<div >
<label asp-for="BasePrice" ></label>
<input asp-for="BasePrice" />
<span asp-validation-for="BasePrice" ></span>
</div>
<div >
<label asp-for="Quantity" ></label>
<input asp-for="Quantity" />
<span asp-validation-for="Quantity" ></span>
</div>
<div >
<label asp-for="PublishingCompanyId" ></label>
<select asp-for="PublishingCompanyId" asp-items="ViewBag.PublishingCompanyId"></select>
<span asp-validation-for="PublishingCompanyId" ></span>
</div>
<div>
@Html.Partial("_EditBookCategory", teste)
</div>
<div >
<input type="submit" value="Save" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
my partial view that work (but in this way just pre-select one category item)
@model MVC_Library.Models.BookCategory
<div >
<div >
<label asp-for="CategoryId" ></label>
<select multiple asp-for="CategoryId" name = "BookCategory[]" asp-items="ViewBag.SelectedCategory"></select>
</div>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
and my controller edit part
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var book = await _context.Books.FindAsync(id);
if (book == null)
{
return NotFound();
}
List<BookCategory> bookCategory = _context.BookCategories.Where(e => e.BookId == id).ToList();
ViewData["PublishingCompanyId"] = new SelectList(_context.PublishingCompanies, "PublishingCompanyId", "PublishingCompanyName", book.PublishingCompanyId);
//this is what i try for try return mutiple category select (don't work with this viewbag)
/* ViewBag.SelectedCategory = new MultiSelectList(_context.Categories.ToList(), "CategoryId", "CategoryName", bookCategory); */
//this viewbag return only one category selected but work
ViewBag.testeview = bookCategory.First();
return View(book);
}
Just once selected (the first), but a want to return all. Need help if this could possible.
CodePudding user response:
If you want to display all the related categories selected:
- Be sure
asp-for="CategoryId"
hereCategoryId
should be type ofint[]
orstring[]
. Or just removeasp-for
tag helper, because you have addedname="BookCategory[]"
here, it will overrideasp-for
generated name attribute. When you form submit, your action always need contain a parameter namedBookCategory[]
, no matter you addasp-for
or not.
Besides BookCategory[]
is not a correct name with no index in array, it should be BookCategory
or any other name and the parameter name in action should be type of int[]
or string[]
. Guessing you may want to match the selected value to List model BookCategory
's CategoryId. It is not acceptable for multiple select.
Be sure the last parameter in
MultiSelectList
should beint[]
orstring[]
. From your code, thedataValueField
inMultiSelectList
matchesCategoryId
property, so your last parameter should be something likebookCategory.Select(a=>a.CategoryId).ToList()
.ViewBag.SelectedCategory = new MultiSelectList(_context.Categories.ToList(), "CategoryId", "CategoryName", bookCategory.Select(a=>a.CategoryId).ToList());
No need use
ViewBag.testeview
, just change like below:@Html.Partial("_EditBookCategory", new BookCategory())
Whole working demo should be like:
Model:
public class Book
{
public int BookId { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public DateTime PublishDate { get; set; }
public int BasePrice { get; set; }
public int Quantity { get; set; }
public int PublishingCompanyId { get; set; }
public List<BookCategory> BookCategory { get; set; }
}
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public List<BookCategory> BookCategory { get; set; }
}
public class BookCategory
{
public int CategoryId { get; set; }
public int BookId { get; set; }
public Category Category { get; set; }
public Book Book { get; set; }
}
View:
@model Book
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>Book</h4>
<hr />
<div >
<div >
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" ></div>
<input type="hidden" asp-for="BookId" />
<div >
<label asp-for="Title" ></label>
<input asp-for="Title" />
<span asp-validation-for="Title" ></span>
</div>
<div >
<label asp-for="Author" ></label>
<input asp-for="Author" />
<span asp-validation-for="Author" ></span>
</div>
<div >
<label asp-for="PublishDate" ></label>
<input asp-for="PublishDate" />
<span asp-validation-for="PublishDate" ></span>
</div>
<div >
<label asp-for="BasePrice" ></label>
<input asp-for="BasePrice" />
<span asp-validation-for="BasePrice" ></span>
</div>
<div >
<label asp-for="Quantity" ></label>
<input asp-for="Quantity" />
<span asp-validation-for="Quantity" ></span>
</div>
<div >
<label asp-for="PublishingCompanyId" ></label>
<select asp-for="PublishingCompanyId" asp-items="ViewBag.PublishingCompanyId"></select>
<span asp-validation-for="PublishingCompanyId" ></span>
</div>
<div>
//change here....
@Html.Partial("_EditBookCategory", new BookCategory())
</div>
<div >
<input type="submit" value="Save" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Partial View:
@model BookCategory
<div >
<div >
<label asp-for="CategoryId" ></label>
<select multiple name="CategoryId" asp-items="ViewBag.SelectedCategory"></select>
</div>
</div>
Controller:
Note: I just hard-coded the data due to easy testing, it is the same with your get data from database. You just need change like what my comment said, other code is no need change like what I did.
public IActionResult Edit(int? id)
{
var book = new Book()
{
BookId = 1,
PublishDate = DateTime.Now,
Author = "a1",
BasePrice = 34,
PublishingCompanyId = 1,
Quantity = 23,
Title = "aa"
};
List<BookCategory> bookCategory = new List<BookCategory>()
{
new BookCategory(){BookId=1,CategoryId=1},
new BookCategory(){BookId=2,CategoryId=1},
new BookCategory(){BookId=2,CategoryId=3}
};
ViewData["PublishingCompanyId"] = new List<SelectListItem>() {
new SelectListItem() { Value = "1", Text = "Elementos1" },
new SelectListItem() { Value = "2", Text = "Elementos2" },
new SelectListItem() { Value = "3", Text = "Elementos3" }
};
var c = new List<Category>()
{
new Category(){CategoryId=1,Name="aa"},
new Category(){CategoryId=2,Name="bb"},
new Category(){CategoryId=3,Name="cc"}
};
//change here....
ViewBag.SelectedCategory = new MultiSelectList(c, "CategoryId", "Name", bookCategory.Select(a=>a.CategoryId).ToList());
//ViewBag.testeview = bookCategory.First();
return View(book);
}
[HttpPost]
public IActionResult Edit(int? id,Book book, int[] CategoryId)
{
//do your stuff......
return View();
}
Result:
For how to choose multiple option, you just need press Ctrl
key meanwhile click the option.