Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I post <select multiple> to a List<T> ASP.NET Core

Tags:

c#

.net

In my system I'm trying to send from a select with multiple options to a list I have created in my model, but when I try to send it I always get the empty list in the controller. My goal is to take all the items that have been selected and write them to this list I have created.

My View:

<select class="selectpicker" multiple data-live-search="true" asp-for="ListaResponsaveis">
<option value="147">John</option>
<option value="212">Lum</option>
<option value="33">Ted</option>
</select>

My Model:

public List<Responsaveis> ListaResponsaveis{ get; set; }

        public class Responsaveis
        {
            public string Login {  get; set; }
        }

My Controller:

public async Task<IActionResult> CadastrarTarefa(WebdeskTarefas webdeskTarefas)

I get the empty list as in the image:

enter image description here

Any suggestions on how I can link the selected options to the list I have created?


1 Answers

ASP.NET's form-data binding can't translate from posted <form> values to classes without a custom ModelBinder - so this means that ASP.NET does not know how to translate from 147 to Responsaveis.Login = "147".

That said, you don't need your public class Responsaveis at all - change your view-model's collection-type to List<String> or List<Int32>:

class MyViewModel
{
    public List<Int32> ListaResponsaveis { get; set; }
}

If you're using ListaResponsaveis for both a two-way form-binding and for displaying strongly-typed data then you need to use two separate collections: one for you to populate in your controller-actions and another that ASP.NET will bind to. The alternative is having to write your own model-binder and it really isn't worth the effort.

class MyViewModel
{
    // GET: Populated by the controller-action.
    // POST: Populated by ASP.NET.
    public List<Int32> ListaResponsaveis { get; set; }

    // GET: Populated by the controller-action.
    // POST: Populated by the controller-action.
    [BindNever] // <-- To prevent malicious users injecting their own data
    public List<Responsaveis> ListaResponsaveisData { get; set; }
}

Your controller actions should look something like this;

[Route("/foo")]
public async Task<IActionResult> GetPage()
{
    List<Responsaveis> data = await this.db.LoadDataAsync();

    //

    MyViewModel vm = new MyViewModel()
    {
        vm.ListaResponsaveis = data
            .Select( d => d.SomeId )
            .ToList(),

        vm.ListaResponsaveisData = data
    };

    return this.View( "ViewName", model: vm );
}

[Route("/foo")]
[HttpPost]
public async Task<IActionResult> PostPage( [FromForm] MyViewModel model )
{
    List<Responsaveis> data = await this.db.LoadDataAsync();

    //

    model.ListaResponsaveisData = data;

    return this.View( "ViewName", model: model );
}
like image 105
Dai Avatar answered Jan 29 '26 08:01

Dai