2016-09-24 12 views
0

我有一个窗体,需要从窗体中的复选框捕获值。每个复选框都应该有一个整数值,当提交表单时,视图模型应该验证这些值,并且至少应该选择一个。如何正确使用ViewModel在捕获输入记录时构建与视图的双向绑定?

我还需要构建一个双向绑定,以便框架自动选择页面加载时选择的选项。

这里是我的模型看起来像

public class SomeViewModel 
{ 
    [Required(ErrorMessage = "You must select at least one site.")] 
    [Display(Name = "All site to have access too")] 
    public int[] Sites { get; set; } 
} 

的我概括了我的ViewModel名为Presenter演示类,像这样

public class Presenter 
{ 
    public SomeViewModel Access { get; set; } 

    public IEnumerable<Site> AvailableSites { get; set; } 
} 

现在,我通过Presenter我的看法,并希望呈现

这里是我的观点如何看起来像

<div class="form-group"> 

    @Html.LabelFor(m => m.Access.Sites, new { @class = "col-sm-2 control-label" }) 

    <div class="col-sm-10"> 

     @for (int i = 0; i < Model.AvailableSites.Count(); i++) 
     { 
      <label class="radio-inline"> 
       @Html.CheckBoxFor(m => m.Access.Sites[i]) 
      </label> 
     } 

    </div> 

    @Html.ValidationMessageFor(m => m.Access.Sites) 
</div> 

因为@Html.CheckBoxFor接受布尔值,我传递一个整数我得到在视图内的@Html.CheckBoxFor(m => m.Access.Sites[i])行的错误。

我该如何解决这个问题?以及如何正确呈现此视图中的复选框?

+0

使用编辑器模板。看看[如何知道从HttpPost创建操作方法中选择的复选框?](http://stackoverflow.com/questions/38961222/how-to-know-the-selected-checkboxes-from-within-the -httppost-create-action-metho) – Shyju

+0

你是说我不能做双向绑定,我必须手动检查选定的值吗? – Jaylen

回答

1

正如您所发现的,您只能使用CheckBoxFor()绑定到bool属性。它有点不清楚,为什么你有2楼这一观点的模型时,你可以通过只使用

public class Presenter 
{ 
    [Required(ErrorMessage = "You must select at least one site.")] 
    [Display(Name = "All site to have access too")] 
    public int[] Sites { get; set; 
    public IEnumerable<Site> AvailableSites { get; set; } 
} 

一种选择,你可以考虑把它简化(基于上述模型和假设的Site类型包含属性int IDstring Name

更改视图以手动生成<input type="checkbox" />元件

@foreach(var site in Model.AvailableSites) 
{ 
    // assumes your using Razor v2 or higher 
    bool isSelected = Model.Sites.Contains(s.ID); 
    <label> 
     <input type="checkbox" name="Sites" value="@site.ID" checked = @isSelected /> 
     <span>@s.Name</span> 
    </label> 
} 
@Html.ValidationMessageFor(m => m.Sites) 

@Html.LabelFor(m => m.Sites)是不合适的。 A <label>是用于将焦点设置到其关联的表单控件的可访问性元素,并且您没有Sites的表单控件。您可以使用​​

一个更好的选择(和MVC方式)是创建一个视图模型代表您可以在视图

public class SiteVM 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public bool IsSelected { get; set; } 
} 

,并在你的GET方法想要的东西,基于所有可用返回List<SiteVM>站点(例如

List<SiteVM> model = db.Sites.Select(x => new SiteVM() { ID = x.ID, Name = x.Name }; 
return View(model); 

,并在视图中使用一个for循环的EditorTemplate(参照this answer更多细节)来生成视图

@model List<SiteVM> 
.... 
@using (Html.BeginForm()) 
{ 
    for(int i = 0; i < Model.Count; i++) 
    { 
     @Html.HiddenFor(m => m[i].ID) 
     @Html.HiddenFor(m => m[i].Name) 
     <label> 
      @Html.CheckBoxFor(m => m[i].IsSelected) 
      <span>@Model[i].Name</span> 
     </label> 
     @Html.ValidationMessage("Sites") 
    } 
    .... 
} 

,然后在POST方法

[HttpPost] 
public ActionResult Edit(List<SiteVM> model) 
{ 
    if (!model.Any(x => x.IsSelected)) 
    { 
     ModelState.AddModelError("Sites", "Please select at least one site"); 
    } 
    if (!ModelState.IsValid) 
    { 
     return View(model); 
    } 
    ... 
} 

在这两种情况下,你不能使用jquery.validate.unobtrusive,因为你没有(也不能)创建这是一个集合的属性表单控件的客户端验证。但是,您可以编写自己的脚本,以显示确认消息并取消默认的提交,例如(假设你使用@Html.ValidationMessageFor(m => m.Sites, "", new { id = "sitevalidation" })

var sitevalidation = $('#sitevalidation'); 
$('form').submit(function() { 
    var isValid = $('input[type="checkbox"]:checked').length > 0; 
    if (!isValid) { 
     sitevalidation.text('Please select at least one site'); 
     return false; // cancel the submit 
    } 
} 
$('input[type="checkbox"]').click(function() { 
    var isValid = $('input[type="checkbox"]:checked').length > 0; 
    if (isValid) { 
     sitevalidation.text(''); // remove validation message 
    } 
} 
相关问题