当我试图在Post中获取值时,当我不按顺序(1,2,3等)检查时,复选框的值被设置为NULL。
我需要选择任何顺序(即4,5)。
MODEL:
public class AssignUsersViewModel
{
[Display(Name = "Check to select")]
public bool Select { get; set; }
public int Id { get; set; }
[Display(Name = "App. Username")]
public string UserName { get; set; }
[Required]
public string GivenName { get; set; }
[Required]
public string Surname { get; set; }
[Display(Name = "Roles")]
public IList<Roles> Roles { get; set; }
}
public class AssignUsersAddModel
{
public bool Select { get; set; }
public int Id { get; set; }
public IEnumerable<SelectedRoles> selectedRoles { get; set; }
}
public class SelectedRoles
{
public string Name { get; set; }
}
CSHTML:
@model IList<AspNetIdentity2DRH.Models.AssignUsersViewModel>
@using (Html.BeginForm("UsersAddToApp", "UsersAdmin", FormMethod.Post))
{
@Html.AntiForgeryToken()
<table class="table">
<tr>
<th>Check for add</th>
<th>Username</th>
<th>Givenname</th>
<th>Surename</th>
<th>Roles</th>
</tr>
@for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>
@Html.CheckBoxFor(x => x[i].Select)
@Html.HiddenFor(x => x[i].Id)
</td>
<td>
@Html.DisplayFor(x => x[i].UserName)
</td>
<td>
@Html.DisplayFor(x => x[i].GivenName)
</td>
<td>
@Html.DisplayFor(x => x[i].Surname)
</td>
<td>
<div class="row">
<div class="form-group">
@for (int j = 0; j < Model[i].Roles.Count(); j++)
{
<div class="col-sm-4">
<input type="checkbox" name="[@i.ToString()].selectedRoles[@j.ToString()].Name" value="@Model[i].Roles[j].Name" class="checkbox-inline" />
@Html.Label(Model[i].Roles[j].Name, new { @class = "control-label", @data_toggle = "tooltip", @data_placement = "top", @data_original_title = Model[i].Roles[j].Description })
</div>
}
</div>
</div>
</td>
</tr>
}
</table>
<p>
<input type="submit" value="Add existing user" class="btn btn-primary" />
<input type="button" value="Cancel" onclick="window.location.href = '@Url.Action("UsersIndex", "UsersAdmin")';" class="btn btn-cancel" />
</p>
}
控制器:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UsersAddToApp(List<AssignUsersAddModel> model)
{
if (ModelState.IsValid)
{
foreach (AssignUsersAddModel item in model)
{
if (item.Select)
{
using (DbContextTransaction dbtrans = db.Database.BeginTransaction())
{
try
{
int appId = (int)Session["ApplicationId"];
Users user = UserManager.FindById(item.Id);
db.ApplicationUsers.Add(new ApplicationUsers { ApplicationId = appId, UserId = user.Id });
db.SaveChanges();
foreach (SelectedRoles RolesItem in item.selectedRoles)
{
int roleId = db.Roles.Where(r => r.Name == RolesItem.Name).Select(r => r.Id).FirstOrDefault();
db.UserApplicationRoles.Add(new UserApplicationRoles { ApplicationId = appId, UserId = user.Id, RoleId = roleId });
db.SaveChanges();
}
dbtrans.Commit();
}
catch (Exception)
{
dbtrans.Rollback();
}
}
}
}
return RedirectToAction("UsersAddToApp");
}
ModelState.AddModelError("", "An error has occurred. Contact system administrator.");
return RedirectToAction("UsersAddToApp");
}
问题是当我选择复选框时(除了第一个,或最后一个在中间,行:
foreach (SelectedRoles RolesItem in item.selectedRoles)
发送item.selectedRoles为空。
我怎么能做到这一点?
答案 0 :(得分:5)
DefaultModelBinder
只会绑定集合项的索引器从零开始并且是连续的集合。您的问题是您手动创建复选框元素。由于未选中的复选框不会回发,如果您取消选中,则在您提交时,它和任何后续复选框值都不会绑定到该集合。
接下来尝试将复选框绑定到string
值。复选框有2个状态,用于表示布尔值。
您尚未向您显示Role
(查看)模型,但它应包含一个boolean
属性,表明它是否已被选中
public class Role
{
public int ID { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
然后在视图中,使用强类型html助手,以便获得正确的双向模型绑定
@for (int j = 0; j < Model[i].Roles.Count; j++)
{
@Html.HiddenFor(m => m[i].Roles[j].Name) // or better use the ID property
@Html.CheckBoxFor(m => m[i].Roles[j].IsSelected)
@Html.LabelFor(m => m[i].Roles[j].IsSelected, Model[i].Roles[j].Name)
}
然后在POST方法中,您的集合将被正确绑定,您可以使用say,
访问所选角色List<string> selectedRoles = model.Roles.Where(r => r.IsSelected);
注意您可能还想为Role.ID
(而不是Role.Name
属性)包含隐藏输入,因此您不需要在POST方法foreach
循环中执行数据库查找
旁注:您的帖子方法需要
public ActionResult UsersAddToApp(List<AssignUsersViewModel> model)
不是ListAssignUsersAddModel> model
答案 1 :(得分:1)
很好的接受答案 - 这是关于复选框和装订的附加说明。
如果查看CheckBoxFor
的输出,您会看到字段中有两个输入,例如:
@Html.CheckBoxFor(x=>x.Flag)
给出
<input type='checkbox' name='Flag' .. // value etc based existing value
<input type='hidden' name='Flag' value='false' /> // always false
这是因为未发送的复选框不会包含在帖子中,因此第二个隐藏字段会向控制器提供false(未标记)值。
当您手动创建input
时,您也可以添加此hidden field
,然后它将返回false值,然后模型绑定器应该按照您原先的预期进行拾取:
<input type="checkbox" name="[@i.ToString()].selectedRoles[@j.ToString()].Name" value="@Model[i].Roles[j].Name" class="checkbox-inline" />
<input type="hidden" name="[@i.ToString()].selectedRoles[@j.ToString()].Name" value="@Model[i].Roles[j].Name" value='false' />
在问题的情况下,我肯定会根据接受的答案重构和使用Html助手。
在其他情况下,可以通过javascript动态添加复选框,因此上面隐藏的输入字段是可行的。
答案 2 :(得分:0)
我发现IEnumerable没有按顺序工作(好消息)
儿子我将复选框的名称更改为:
然后在控制器中,对于每一个可枚举的项目,我都可以得到以下内容
返回(以逗号分隔)带有所选项名称的字符串。
到目前为止,我没有其他想法,但它适用于我...我只需要在name属性中限制逗号。