I am a newbie in asp.net core mvc. Trying to make a simple update page where the model (coming from another data service) is bound with a table. On each row there is a update button. There are some fields which are mapped to the text box and are editable.
I want to get the editable values in text box within the controller without using jquery or ajax. I am sure there must be a way in plain asp.net core capabilities.
Model:
public class Employee
{
public string Name { get; set; }
public string Location { get; set; }
}
View:
@model IEnumerable<AspNetCoreMVC.Models.Employee>
@{
ViewData["Title"] = "Home";
}
<table style="width:fit-content">
<thead>
<tr>
<th>
@Html.DisplayNameFor(Model => Model.Name)
</th>
<th>
@Html.DisplayNameFor(Model => Model.Location)
</th>
<th>
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@item.Name
</td>
<td>
@Html.TextBoxFor(m => item.Location)
</td>
<td>
@Html.ActionLink("Update","UpdateAction","Home",new { updatedLocation = item.Location })
</td>
</tr>
}
</tbody>
</table>
Controller:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using AspNetCoreMVC.Models;
namespace AspNetCoreMVC.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
var employees = new List<Employee>();
employees.Add(new Employee { Name="Abcd", Location="abcdLocation1"});
employees.Add(new Employee { Name = "Efgh", Location = "EfghLocation2" });
return View(employees);
}
public IActionResult UpdateAction(string updatedLocation)
{
var employees = new List<Employee>();
employees.Add(new Employee { Name = "Abcd", Location = "abcdLocation1" });
employees.Add(new Employee { Name = "Efgh", Location = "EfghLocation2" });
return View("Index", employees);
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
Currently I only get the same value as bound by the cell template textbox. How can I make sure the changed text in the textbox location is received in the controller please ?
CodePudding user response:
In my case this worked when I used the @Html.EditorFor()
helper instead of the @Html.TextBoxFor()
helper, with setting the name
attribute.
Therefore, try the following:
<tbody>
@foreach (var item in Model)
{
@using (Html.BeginForm("UpdateAction", "Home"))
{
<tr>
<td>
@item.Name
</td>
<td>
@* Setting the `name` attribute explicitly *@
@Html.EditorFor(m => item.Location, "name", "updatedLocation")
</td>
<td>
<div><input type="submit" value="Update" /></div>
</td>
</tr>
}
}
</tbody>
Because of the binding context will already have the updatedLocation
name, you don't need to define it in the Html.BeginForm()
.
And the [HttpPost]
attribute should be added to theUpdateAction()
action method declaration:
[HttpPost]
public IActionResult UpdateAction(string updatedLocation)
{
...
}
NOTE: An additional option is using the <input>
tag instead of @Html.EditorFor()
helper:
<input id="updatedLocation" name="updatedLocation" type="text" value="@item.Location" />
CodePudding user response:
Try to add a form outside <tr>
:
<tbody>
@foreach (var item in Model)
{
<form asp-action="UpdateAction" asp-controller="Home" >
<tr>
<td>
@item.Name
</td>
<td>
@Html.TextBoxFor(m => item.Location)
</td>
<td>
<input type="submit" value="Update" />
</td>
</tr>
</form>
}
</tbody>
And because name attribute bind with the property name in action,try to change your action like this:
public IActionResult UpdateAction(string Location)
{
var employees = new List<Employee>();
employees.Add(new Employee { Name = "Abcd", Location = "abcdLocation1" });
employees.Add(new Employee { Name = "Efgh", Location = "EfghLocation2" });
return View("Index", employees);
}