c# - 使用模型绑定和 POST 请求在每个表行上实现删除按钮
问题描述
在我看来,我有一个表格,我想用它来删除特定的行。我使用一个 foreach 循环来生成一个隐藏的输入字段,其中包含我想要传递给控制器和asp-for
标签以进行模型投标的行值,以及一个提交按钮。
传递给控制器的值始终是第一行。我倾向于认为这种行为的原因是生成的输入字段都具有相同的 name 属性,因为asp-for
表达式对于 foreach 循环的每次迭代都是不变的。
有没有一种直接的方法可以使用表单和 POST 请求来实现这一点,或者我应该只使用带有路由值的锚点,即 GET 请求?
这是我的视图模型:
public class RolesViewModel
}
public IList<AppUser> UsersInRole {get; set;}
public string SelectedRole {get; set;}
public RemoveUserFromRole RemoveUser {get; set;}
public class RemoveUserFromRole
{
public string UserName {get; set;}
public string RoleName {get; set;}
}
}
我的观点
<form method="post" asp-action="RemoveUser" id="removeUserForm"></form>
<table id="userTable" class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">User name</th>
<th scope="col" class="text-center">Delete</th>
</tr>
</thead>
<tbody>
@foreach (var user in Model.UsersInRole)
{
<tr>
<td>@user.UserName</td>
<td class="text-center">
<input form="removeUserForm" asp-for="RemoveUser.UserName" type="hidden" value="@user.UserName" />
<input form="removeUserForm" asp-for="RemoveUser.RoleName" type="hidden" value="@Model.SelectedRoleName" />
<button form="removeUserForm" type="submit" class="btn btn-sm btn-link text-danger py-0 my-0">
<i class="fas fa-times"></i>
</button>
</td>
</tr>
}
</tbody>
</table>
我在控制器中的操作方法
[HttpPost]
public async Task<IActionResult> RemoveUser(RolesViewModel model)
{
//model.RemoveUser.UserName always have the value from the first row
var user = await _userManager.FindByNameAsync(model.RemoveUser.UserName);
if (user == null)
return RolesError(await GetModel());
var result = await _userManager.RemoveFromRoleAsync(user, model.RemoveUser.RoleName);
if (!result.Succeeded)
return RolesError(await GetModel());
return RedirectToAction("Roles", new { roleName = model.RemoveUser.RoleName });
}
在此先感谢您的时间。
解决方案
根据您的代码,我发现您有多个隐藏文件,其中包含user.UserName
.
如果你点击提交按钮,它会将所有隐藏的字段值上传到代码隐藏中,它只会绑定第一个,这就是你的模型总是第一个的原因。
您可以在 F12 开发工具的网络中找到 formdata。
为了解决这个问题,我们有一个简单但不是很好的解决方案。
我们可以在您的表格中设置多个表单标签,以避免将所有隐藏的用户名值发布到控制器:
如下所示:
<table id="userTable" class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">User name</th>
<th scope="col" class="text-center">Delete</th>
</tr>
</thead>
<tbody>
@foreach (var user in Model.UsersInRole)
{ int i = 0;
<tr>
<td>@user.UserName</td>
<td class="text-center">
<form method="post" asp-action="RemoveUser" id="@user.UserName">
<input form="@user.UserName" name="RemoveUser.UserName" type="hidden" value="@user.UserName" />
<input form="@user.UserName" name="RemoveUser.RoleName" type="hidden" value="@Model.SelectedRole" />
<button form="@user.UserName" type="submit" class="btn btn-sm btn-link text-danger py-0 my-0">
<i class="fas fa-times">iiiii</i>
</button>
</form>
</td>
</tr>
}
</tbody>
</table>
如果您选择这种方式,您应该重建所有视图的 html 构成。
此外,您可以尝试使用 ajax 来实现您的要求,这个解决方案比以前的解决方案要好。您可以使用 jquery 根据提交按钮的 id 或位置获取正确的表单数据,然后使用 jquery ajax 将表单数据发布到控制器中。然后你可以返回重定向 url 而不是RedirectToAction
方法。
更多关于如何使用 ajax 发送表单数据的详细信息,您可以参考以下代码:
@model MVCRelatedIssue.Models.RolesViewModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<form method="post" asp-action="RemoveUser" id="removeUserForm">
<table id="userTable" class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">User name</th>
<th scope="col" class="text-center">Delete</th>
</tr>
</thead>
<tbody>
@foreach (var user in Model.UsersInRole)
{
<tr>
<td>@user.UserName</td>
<td class="text-center">
<input form="removeUserForm" name="RemoveUser.UserName" type="hidden" value="@user.UserName" />
<input form="removeUserForm" name="RemoveUser.RoleName" type="hidden" value="@Model.SelectedRole" />
<button form="removeUserForm" type="submit" id="submit" class="btn btn-sm btn-link text-danger py-0 my-0 subbtn">
<i class="fas fa-times">iiiii</i>
</button>
</td>
</tr>
}
</tbody>
</table>
</form>
@section Scripts{
<script>
$(document).ready(function () {
$(".subbtn").bind("click", function (e) {
e.preventDefault();
var formdata = new FormData();
var UserName = $(this).prev().prev().val();
formdata.append("RemoveUser.UserName", UserName);
console.log(UserName);
var roleName = $(this).prev().val();
formdata.append("RemoveUser.RoleName", roleName);
console.log(roleName);
$.ajax({
type: "POST",
url: "/RemoveUser/RemoveUser",
data: formdata,
contentType: false,
processData: false,
success: function (data) {
alert("success");
window.location.href = data;
}
});
});
});
</script>
}
控制器:
[HttpPost]
public async Task<IActionResult> RemoveUser(RolesViewModel model)
{
//model.RemoveUser.UserName always have the value from the first row
//var user = await _userManager.FindByNameAsync(model.RemoveUser.UserName);
//if (user == null)
// return RolesError(await GetModel());
//var result = await _userManager.RemoveFromRoleAsync(user, model.RemoveUser.RoleName);
//if (!result.Succeeded)
// return RolesError(await GetModel());
string redirecturl = "/RemoveUser/Roles?roleName=" + model.RemoveUser.RoleName;
return Ok(redirecturl);
}
结果:
推荐阅读
- ruby-on-rails - Rails 无法在开发环境中从 /public 提供基于 erb 的模板
- python - CV2在没有matchTemplate的图像中找到对象
- laravel - 为什么我在尝试下载文件时出现此页面错误?
- python - 类型错误:对象 DataFrame 不能在“等待”表达式中使用
- ios - XamarinIOS RestAPI 请求 System.NullReferenceException
- node.js - Sequelize - 使用 NodeJs 查询外键字段
- xaml - 使用 XAML 和 C++/WinRT 时,IDL 中必须包含哪些属性/函数?
- reactjs - MUI 自动完成,用键盘滚动需要突出显示
- python - 客户端库通常会实现重试机制吗?
- android - AdColony SDK 集成 - Admob 中介 - Flutter - Kotlin