6

So, basically the aim is:

User selects multiple 'categories' for a book (genres) from a select list. Some examples are:

  • Action and Adventure
  • Classics
  • Comic Book or Graphic Novel

After the user selects 1 or more (so multiple), they save the book to a database.

Functiality wise, everything worked just fine when I was dealing with singular genres (the genre was saved as a single string), but I need to have support for multiple genres.

The first thing I did was simply change the string Category to List<string> Categories, but that caused the error seen here: StackOverflow issue, which was solved I tried the solution that 'TuPack' offered, and that error went away... but it led to a whole new issue.

You're up to speed on where I am now: In order to get any results out of my <select></select> , I have to do this:

<select asp-for="CategoryIds[0].CategoryId" asp-items="ViewBag.Language"
        class="form-control" multiple="multiple">
   <option value="">Please choose book language</option>                    
</select>

That certainly works.. for getting the first category the user selects. That's all though.

As for the code so far, relevance wise... I'll cut off the db related stuff, since the issue occurs long before there:

Controller:

public async Task<ViewResult> AddNewBookAsync(bool isSuccess = false, int bookId = 0)
        {
            var model = new BookModel();
            
            ViewBag.Language = new SelectList(await _languageRepository.GetLanguages(), "Id", "Name");

            ViewBag.IsSucess = isSuccess;
            ViewBag.BookId = bookId;            
            return View(model);
        }

        [HttpPost]
        public async Task<IActionResult> AddNewBook(BookModel bookModel)
        {


            if (ModelState.IsValid)
            {
                int id = await _bookRepository.AddNewBook(bookModel);
                if(id > 0)
                {
                    return RedirectToAction(nameof(AddNewBook), new { isSuccess = true, bookId = true });
                }
            }



            ViewBag.Language = new SelectList(await _languageRepository.GetLanguages(), "Id", "Name");
            return View();
        }

BookModel:

public class BookModel
    {
        public int Id { get; set; }
        [StringLength(100, MinimumLength = 5)]
        [Required(ErrorMessage ="Please enter the title of your book")]
        public string Title { get; set; }
        [Required(ErrorMessage = "Please enter the author's name")]
        public string Author { get; set; }
        [StringLength(500)]
        public string Description { get; set; }
        
        [Required(ErrorMessage = "Please choose the language of your book")]
        public string Language { get; set; }
        [Display(Name = "Genre")]
        public List<Categories> CategoryIds { get; set; } = new List<Categories>();

        [Required(ErrorMessage = "Please enter the total pages")]
        [Display(Name = "Total pages of book")]
        public int? TotalPages  { get; set; }
    }

I showed the relevant Html code previously, so won't post it again.

Visuals: Example Input: Example Input Current Output: Current Output

Category Id 1 is 'Action And Adventure'.

By the way, I'm sure it is quite easy to tell, but this is just a 'practice project'. I don't want to make big changes to the main project I'm working on without actually knowing what I'm doing.

Update: After changing CategoryIds[0].CategoryId and running it with the exact same values as before, I get: 0 object results

1 Answer 1

6

Update

enter image description here

I used to add a IList<SelectListItem> property to Book model and store multiple categories in CategoryIds property. It works on me.

Codes of controller

    public IList<SelectListItem> GetCategories()
    {
        var categories = new List<Category>
        {
            new Category {Id = 1, CategoryName = "Action and Adventure"},
            new Category {Id = 2, CategoryName = "Classics"},
            new Category {Id = 3, CategoryName = "Comic Book or Graphic Novel"},
        };  // here you can load categories from DB, this is only for test
        


        var categoryListItem = categories
       .Select(x => new SelectListItem { Text = x.CategoryName, Value = x.Id.ToString() })
       .ToList();

        return categoryListItem;
    }


    [Route("/books/add")]
    public IActionResult _AddNewBooks()
    {
        var model = new BookModel { CategoryList = GetCategories() };

        return View(model);
    }


    [Route("/books/addnewbook")]
    [HttpPost]
    public IActionResult AddNewBook(BookModel model)
    {
        if (ModelState.IsValid)
        {
            //int id = await _bookRepository.AddNewBook(bookModel);
            //if (id > 0)
            //{
            //    return RedirectToAction(nameof(AddNewBook), new { isSuccess = true, bookId = true });
            //}
        }

        //ViewBag.Language = new SelectList(await _languageRepository.GetLanguages(), "Id", "Name");
        model.CategoryList = GetCategories();

        return View();

    }

Codes of model

public class BookModel
{
    public int Id { get; set; }

    public string Title { get; set; }

    public IList<SelectListItem> CategoryList { get; set; }

    [Required(ErrorMessage = "Please select at last 1 Category")]
    public List<int> CategoryIds { get; set; }


    public BookModel(){
        CategoryList = new List<SelectListItem>();
    }
}


public class Category
{
    public int Id { get; set; }
    public string CategoryName { get; set; }
}

Codes of view

<select asp-for="CategoryIds" asp-items="Model.CategoryList" 
           placeholder="Select Categories" 
           onchange="console.log($(this).children(':selected').length)" 
           class="search-box form-control">
</select>




@MJDeveloping,

1> You are using ViewBag.Language as items of Category. I suggest you return Categories to the view.

2> asp-for should be CategoryIds.

<select asp-for="CategoryIds" asp-items="ViewBag.Language"
        class="form-control" multiple="multiple">
   <option value="">Please choose book language</option>                    
</select>
Sign up to request clarification or add additional context in comments.

9 Comments

Opps! That Language is left over from the lesson I'm following - They did languages as a select... but it didn't make too much sense to be able to select multiple languages, so I swapped it to categories
In regards to using "CategoriesIds" though- I get 0 objects in the List. Will edit post with a picture.
Hi,@ MJDeveloping, the relationship between Book and Category has change to Many to Many from your description. And you could try to use build new model in new relationship. Please feel free to ask if you have any questions with it.
Thanks, @Lightman. I've gone ahead and created a Many to Many relationship.. after opening it up in SSMS, I've confirmed that both the Books and Categories table have a one to many relationships to the BookCatagories table. Currently: asp-for="Categories" and "Categories" is public List<BookCatagory> Categories {get; set;} Oh right, I should probably mention: The source of the categories is a DB, not a enum or hardcoded in the program.
Opps-forgot the importance bit- the end result looked no different to the start-if I select a certain element, it works, but trying to operate on the whole array returns 0 results
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.