zaza
zaza

Reputation: 912

How to bind form inputs to dictionary values

I'm creating an ASP.NET core razor page web app, one of the pages need to be able to modify a Dictionary<string, string> property.

The object i am trying to modify is as follows:

public class Element
{
    [Key]
    public string ID {get;set;}
    public Dictionary<string, string> Values = new Dictionary<string, string>(); 
}

I am able to dispay the values on the page using the following code:

<form method="POST">
    <ul>
        <li hidden="true">ID: <input asp-for="FocusedItem.ID"/></li>
        @for (int i = 0; i < Model.FocusedItem.Values.Count(); i++)
        {
            <li>@Model.FocusedItem.Values.ElementAt(i).Key: <input asp-for="@Model.FocusedItem.Values.ElementAt(i).Value"/></li>
        }
    </ul>
    <br />
    <input type="submit" value="Submit" />
</form>

The pagemodel cointains the following method to handle post events:

public void OnPost(Element FocusedItem)
{
}

The "ID" property is populated properly, however, the "Values" property has a count of 0 (the input values on the form are not binding to the Dictionaty). How can this be resplved?

Also bonus question - how can one add a new element to the dictionary?

Edit: Code - -cshtml: https://raw.githubusercontent.com/thezaza101/RDMUI/master/Pages/Data/ElementManager.cshtml -cs: https://raw.githubusercontent.com/thezaza101/RDMUI/master/Pages/Data/ElementManager.cshtml.cs

Upvotes: 2

Views: 9059

Answers (1)

Chris Pratt
Chris Pratt

Reputation: 239430

@MarkG was close, but the actual syntax would be: Values[N].Key and Values[N].Value, where N is your index. However, since you're using tag helpers to generate the fields, the true problem is your use of ElementAt. Model expressions cannot include arbitrary methods, as there's no way to bind to something like ElementAt in the resultant POST handling. Instead, you must use the indexing syntax, i.e. [i]. However, there's where using a dictionary breaks down, as it can't be indexed by item position - only key.

Honestly, I tend to avoid posting dictionaries, as it's unstructured data. 99.99% of the time you'd probably be better served by breaking that off into a class with properties instead of a dictionary of keys. If you insist on using a dictionary, you can try passing the actual key values as indexers:

@foreach (var key in Model.Values.Keys)
{
    <input asp-for="Values[key]" />
}

I haven't tried that personally, but I think it should work. Short of that, the only way I know works is generating the input names manually:

<input name="Values[@i].Key" value="@Model.Values.ElementAt(i).Key" />
<input name="Values[@i].Value" value="@Model.Values.ElementAt(i).Value" />

Upvotes: 12

Related Questions