Reputation: 29
I have a View whose model is a List of custom types and I want to POST changes for only a single element of the List (model[i]). This POST itself works, except the value is what was originally in the model and not the updated value from the input
View's Model Declaration
@model List<Translation2>
Translation2's type (F#)
type Translation2 = {
Key: string;
RowKey: string;
Value: string;
English: string;
}
The View with a single entity submit
@model List<Translation2>
<form asp-controller="Home" asp-action="Translate" method="POST" >
<table>
<thead>
<th>
<h2>Key</h2>
</th>
<th>
<h2>English</h2>
</th>
<th>
<h2>Translated</h2>
</th>
</thead>
<tbody>
@for(var i = 0; i < Model.Count(); i++)
{
<tr>
<div>
<td class="key-col">
<p style="font-size:large">@Model[i].Key</p>
@Html.HiddenFor(m => m[i].RowKey)
</td>
<td class="val-col">
<input class="fill-void" type="text" asp-for="@Model[i].English" readonly />
</td>
<td class="val-col">
<input class="fill-void" type="text" asp-for="@Model[i].Value" />
</td>
<td>
<a href="@Url.Action("Translate", "Home", new {RowKey=@Model[i].RowKey, Key=@Model[i].Key, Value=@Model[i].Value })" >Save Translation</a>
</td>
</div>
</tr>
}
</tbody>
</table>
</form>
I have also tried to just POST the entire list per ASP.NET Core 1.0 POST IEnumerable<T> to controller but will get
ArgumentNullException: Value cannot be null.
Parameter name: source
Count
MoveNext in Translate.cshtml
@for(var i = 0; i < Model.Count(); i++)
The View with submitting the entire list
@model List<Translation2>
<form asp-controller="Home" asp-action="Translate" method="POST" >
<table>
<thead>
<th>
<h2>Key</h2>
</th>
<th>
<h2>English</h2>
</th>
<th>
<h2>Translated</h2>
</th>
</thead>
<tbody>
@for(var i = 0; i < Model.Count(); i++)
{
<tr>
<div>
<td class="key-col">
<p style="font-size:large">@Model[i].Key</p>
@Html.HiddenFor(m => m[i].RowKey)
</td>
<td class="val-col">
<input class="fill-void" type="text" asp-for="@Model[i].English" readonly />
</td>
<td class="val-col">
<input class="fill-void" type="text" asp-for="@Model[i].Value" />
</td>
<td>
<button type="submit">Save Translation</button>
</td>
</div>
</tr>
}
</tbody>
</table>
</form>
I would really like to know how to solve both ways, if possible, but a solution for either will do at this point.
Upvotes: 1
Views: 2959
Reputation: 29
@Nkosi 's comment on the OP is the correct answer
"That action is doing a GET and not a POST. the value in the link does not change after render when you update the input field. Suggestion. wrap each tr in it's own form that submits to an action expecting a single model and not a collection"
Corrected Code:
@for(var i = 0; i < Model.Count(); i++)
{
<form asp-controller="Home" asp-action="Translate" method="POST" >
<tr>
<div>
<td class="key-col">
<p style="font-size:large">@Model[i].Key</p>
@Html.HiddenFor(m => m[i].RowKey)
</td>
<td class="val-col">
<input class="fill-void" type="text" asp-for="@Model[i].English" readonly />
</td>
<td class="val-col">
<input class="fill-void" type="text" asp-for="@Model[i].Value" />
</td>
<td>
<button type="submit">Save Translation</button>
</td>
</div>
</tr>
</form>
}
Still getting an error ArgumentException: Type 'Translation2' does not have a default constructor Parameter name: type, but the scope of this question has been resolved.
Update: Partial Fix ---
Have added the constructors, however it always uses the default constructor so when I look at the property values after the POST, they all say "DEFAULT"
type Translation2(key:string, rowKey:string, value:string, english:string) =
public new () = Translation2("DEFAULT", "DEFAULT", "DEFAULT", "DEFAULT")
member this.Key = key
member this.RowKey = rowKey
member this.Value = value
member this.English = English
Update: For the record --- complicating the constructor doesn't help either... it seems the values aren't being lifted from the view....
type Translation2(key:string, rowKey:string, value:string, english:string) =
let mutable k = key
let mutable r = rowKey
let mutable v = value
let mutable e = english
member this.Key with get() = k and set(value) = k <- value
member this.RowKey with get() = r and set(value) = r <- value
member this.Value with get() = v and set(value) = v <- value
member this.English with get() = e and set(value) = e <- value
public new () = Translation2("DEFAULT", "DEFAULT", "DEFAULT", "DEFAULT")
Upvotes: 1