AlexGH
AlexGH

Reputation: 2817

pass Dictionary<string, List<string>> from View to Controller in MVC

I want to pass some data from my view to my controller, my view looks like this:

  <div id="Section1" class="divFiles">
    <span>Section 1 </span>

<input type="text" name="test[0]">

<input type="text" name="test[1]">

<input type="text" name="test[2]">

<input type="text" name="test[3]">

</div>

  <div id="Section2" class="divFiles">
    <span>Section 2 </span>

<input type="text" name="test[4]">

<input type="text" name="test[5]">

<input type="text" name="test[6]">

<input type="text" name="test[7]">

</div>

But this way I'm just sending a list of strings to my controller, there are not keys and I need key because I need this to be grouped by keys.

I would like to pass my data like a Dictionary, grouped by sections, for example:

Section 1: {"first string", "second string", "third string"}, Section 2: {"fourth string", "fifth string"}

and like that,I'm thinking that the best way to do this probably is sending the data as a Dictionary of type Dictionary<string, List<string>> where Section 1, Section 2 would be the keys and then the list of string their values, how could I do that? I can use JQuery for that purpose too, but I'm not sure of how I must write the html to send the data like that. Doing it this way my parameter in my controller action should be of type Dictionary<string, List<string>> Any suggestions of doing this in a different way is welcome too

Upvotes: 0

Views: 4733

Answers (2)

user3559349
user3559349

Reputation:

For all but a simple Dictionary where both the Key and Value are value types (for example Dictionary<string, int>), the DefaultModelBinder requires that the control names be in the following format (in your case, assuming the POST method signature is public ActionResult XX(Dictionary<string, List<string>> names))

<input name="names[0].Key" value="aaa" ... />
<input name="names[0].Value[0]" value="bbb" ... />
<input name="names[0].Value[1]" value="ccc" ... />
<input name="names[1].Key" value="xxx" ... />
<input name="names[1].Value[0]" value="yyy" ... />
<input name="names[1].Value[1]" value="zzz" ... />

There are no HtmlHelper extension methods that can generate the correct name attributes for a Dictionary containing either a Key and/or a Value that is a complex object or collection,which means that you would need to generate all the html manually and lose all the benefits of strong types binding, client side validation etc.

It would be far easier to create a view model representing your structure, for example

public class ValueVM
{
    public string Name { get; set; }
}
public class GroupVM
{
    public string Key { get; set; }
    public List<ValueVM> Values { get; set; }
}

and then in the GET method initialize a collection of GroupVM, populated with data and pass it to the view, for example

var model = new List<GroupVM>
{
    new GroupVM
    {
        Key = "Section 1",
        Values = new List<ValueVM>
        {
            new ValueVM { Name = "...." },
            new ValueVM { Name = "...." }
        }
    },
    new GroupVM
    {
        Key = "Section 2",
        ....
    }
};
return View(model);

Then in the view

@model List<GroupVM>
....
@using (Html.BeginForm())
{
    @for(int i = 0; i < Model.Count; i++)
    {
        <div>
            <h2>@Model[i].Key</h2>
            @Html.HiddenFor(m => m[i].Key)
            @for (int j = 0; j < Model[i].Values.Count; j++)
            {
                @Html.TextBoxFor(m => m[i].Values[j].Name)
            }
        </div>
    }
    ....
}

And the POST method signature would be

public ActionResult XXXX(List<GroupVM> model)

Upvotes: 3

Greg
Greg

Reputation: 11478

You should create an object, then pass the object to your Controller. It will be far easier, otherwise you'll have a Controller with a massive set of parameters performing a form submission. I would use JavaScript, then simply do an Ajax request.

public class Example
{
     public int Id { get; set; }
     public string Key { get; set; } // Bad name
     public string Value { get; set; } // Bad name
}

So your Controller would expect, Example.

public IActionResult Submit(List<Example> examples)
{
     // Collection of our inputs as an object, manipulate.
}

Then for the JavaScript, you would simply do:

function getFormDataAndCreateObject() {
     var formElements = $('[data-rel="section"]');
     var elements = [];

     $.each(formElements, function (index) {
          elements.push(buildExample(index, formElements[index].attr('name'), formElements[index].value));
     });

     // Either return elements, or simply perform Ajax to send to controller.
}

function buildExample(id, section, name) {
     var examples = [{
          Id : id,
          Section: section,
          Name: name
     }];
}

May have typos, but the concept is what is important.

Upvotes: 2

Related Questions