Home > database >  MVC problem with view of Edit that contain [partial view from relation many to many]
MVC problem with view of Edit that contain [partial view from relation many to many]

Time:03-29

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:

  1. Be sure asp-for="CategoryId" here CategoryId should be type of int[] or string[]. Or just remove asp-for tag helper, because you have added name="BookCategory[]" here, it will override asp-for generated name attribute. When you form submit, your action always need contain a parameter named BookCategory[], no matter you add asp-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.

  1. Be sure the last parameter in MultiSelectList should be int[] or string[]. From your code, the dataValueField in MultiSelectList matches CategoryId property, so your last parameter should be something like bookCategory.Select(a=>a.CategoryId).ToList().

    ViewBag.SelectedCategory = new MultiSelectList(_context.Categories.ToList(), "CategoryId", "CategoryName",
                                            bookCategory.Select(a=>a.CategoryId).ToList());
    
  2. 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:

enter image description here


For how to choose multiple option, you just need press Ctrl key meanwhile click the option.

  • Related