How can i send back a model containing two lists from the view to my controller

55 Views Asked by At

I have a cshtml view, for which I am sending a viewmodel. That viewmodel consist of two list of albums (music albums). I then ask the user to check up to 3 of these albums (a checkbox next to the title) to vote for his favorite music. I use javascript to ensure he doesn't check anymore than 3 (The security is a detail right now, I'm more concerned about getting it to work, but I'm open to suggestion if people have a better solution).

Since all albums are displayed in a table, I would love to send back to the controller through the submit button, the same model after updating it.

Basically, one of the list contain the current vote the user has made before loading the page (can be empty), and the second one should be empty until sent back to the controller containing the list of votes that are currently selected. I then use these two lists to compare them and update the database, removing the votes he removed, and adding the vote he added.

But I am unable to create a proper form to return these informations as I am not used to forms.

I tried to put the whole list in a form, but it didn't work. My reserach when I look for "sending model back to controller" usually do just that and get it to work.

View model

public class CategoryVotesUserViewModels
{
    public CategoryVoteViewModels categoryVoteViewModels;
    public List<int> listVotesEntry = new List<int>();
    public List<int> listVotesOutput = new List<int>();
}

Relevant CSHTML and javascript

@section Header{
    <script>
        var MAX_VOTES = 3;

        function checkNumberVotes($this) {

            console.log($("input[name='listVoteOutput']:checked"));
            if ($("input[name='listVoteOutput']:checked").length > MAX_VOTES) {
                $this.checked = false;
            }
        }
    </script>
}

@using (Html.BeginForm("VoteInCategory", "Votes", new { SearchModel = Model }, FormMethod.Post))
{
    <ul>

        @foreach (var av in Model.categoryVoteViewModels.listVotes)
        {
            <li>
                @av.album.Title | @av.votes |
                <input type="checkbox"
                       name="listVoteOutput"
                       [email protected]
                       onclick="checkNumberVotes(this)"
                       @if (Model.listVotesEntry.Contains(av.album.ID))
                       { <text> checked </text> } />
            </li>
         }
    </ul>
    <div class="form-group text-center">
        <input type="submit" class="btn btn-primary" value="Submit" />
    </div>
}

Controller

[HttpPost]
public ActionResult VoteInCategory(CategoryVotesUserViewModels categoryVotesUserViewModels)
{
    if (ModelState.IsValid)
    {
        List<int> toAdd = categoryVotesUserViewModels.listVotesOutput.Except(categoryVotesUserViewModels.listVotesEntry).ToList();
        List<int> toRemove = categoryVotesUserViewModels.listVotesEntry.Except(categoryVotesUserViewModels.listVotesOutput).ToList();

        VoteService.updateVoteUserCategory(User.Identity.GetUserId(), toRemove, toAdd, categoryVotesUserViewModels.categoryVoteViewModels.categoryID);

        //TODO Redirect to success
        return RedirectToAction("Index", "Home");
     }

    return View(categoryVotesUserViewModels);
}

If the user already had voted, all album whose ID is in "ListVotesEntry" should begin checked. If the user hasn't voted, or voted for nothing previously, "ListVotesEntry" should be empty.

When the User press the submit button, if an album is checked, the album's id should be added to the "ListVotesOutput" list. Also, both "ListVotesEntry" and "ListVotesOutput" should be sent back to the controller. The list with the names of the albums and their titles/ID is no longer necessary for the rest of the treatment

1

There are 1 best solutions below

0
Elgate On

Found the solution. The problem was that my model needed to use "{get; set;}" on its attributes, otherwise the binding doesn't work, which mean that it send back an empty model.