MVC 4创建一个表单,其中列表作为我的新对象的属性

时间:2014-08-06 08:37:03

标签: asp.net-mvc asp.net-mvc-4

我正在创建一个注册新用户的表单,每个用户都可以拥有多个地址。 (许多地址给一个用户)。我发现这篇文章但对我来说不合适,因为我有一个主要属性是用户,地址必须与之相关。我想创建一些类似的东西,即使在新用户的创建屏幕中添加了许多地址,也不存在这些地址的用户主键相关。

http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

有人可以举例说明如何更好的方法吗?

这与我的代码非常接近:

public class Person{
   public int PersonId { get; set; }
   public string Name { get; set; }      
   public virtual ICollection<Address> Addresses { get; set; }
}    
public class Address{
   public int AddressId { get; set; }
   public string Street { get; set; }      

   [ScriptIgnore]
   public virtual Person Person { get; set; }
}

2 个答案:

答案 0 :(得分:2)

正如Klors所说,为地址和人物创建一个视图模型(建议List<AddressVM>PersonVM构造函数中初始化)。在PersonController

[HttpGet]
public ActionResult Create()
{
  PersonVM model = new PersonVM();
  model.Addresses.Add(new AddressVM()); // add an empty address assuming at least one required
  return View(model, "Edit")
}

[HttpGet]
public ActionResult Edit(int ID)
{
  PersonVM model = // get from database/repository
  // If Address.Count == 0, add new Address
  return View(model);
}

[HttpPost]
public ActionResult Edit(PersonVM model)
{
  ...

在你看来

@model PersonVM
@using (Html.BeginForm("Edit", "Person") {
  ....
  @Html.HiddenFor(m => m.ID)
  @Html.TextBoxFor(m => m.Name)
  ... 
  @Html.EditorFor(m => m.Addresses) // you may want to create an editor template for AddressVM
  <button type="button" id="AddAddress">Add address</button>

EditorFor()将生成与此类似的HTML(请注意索引器)

<input type="text" name="Address[0].Street" id="Address_0__Street" ..../>
<input type="text" name="Address[0].Suburb" id="Address_0__Suburb" ..../>

要动态添加新地址,您需要使用JavaScript生成类似的HTML,但增加索引器。如果您使用编辑器模板,则可以将Address控件包装在容器中(例如<div class="address">),这样可以根据下面的脚本轻松选择

动态添加新地址的脚本

$('#AddAddress').click(function() {
  var addresses = $('.address');
  // Get the number of existing address
  var count = addresses.length;
  // Get the first address and clone it
  var clone = addresses.first().clone();
  // Update the index of the clone
  clone.html($(clone).html().replace(/\[0\]/g, '[' + count + ']'));
  clone.html($(clone).html().replace(/"_0__"/g, '_' + count + '__'));
  // Add to the DOM
  addresses.last().after(clone);
}

请注意,这也将克隆第一个地址中的值,因此您可能希望重置部分或全部值,例如(在添加之后)

clone.find('input').val('');

如果您使用的是@Html.ValidationMessageFor()方法,请注意,除非您解析表单,否则不会在浏览器中验证动态添加的元素。可以在此处找到如何执行此操作的示例:jquery.validate.unobtrusive not working with dynamic injected elements

答案 1 :(得分:1)

this这样的东西可能更接近你需要的东西。您需要设想复选框是用于输入地址的字段集合。

但是,如果为Person创建包含ViewModel for Address列表的ViewModel,则可以创建强类型编辑器模板并显示与ViewModel相同的模板,如果使用{{{},则会自动获取它们。 1}}和@Html.EditorFor使得一对多的工作变得更容易。

如果你有这样的文件 -

@Html.DisplayFor

和一个人ViewModel有点像

~/Models/PersonViewModel.cs
~/Models/AddressViewModel.cs
~/Views/Person/Edit.cshtml
~/Views/Shared/DisplayTemplates/AddressViewModel.cshtml
~/Views/Shared/EditorTemplates/AddressViewModel.cshtml

如果您有像

这样的人的编辑视图
public class PersonViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    ...
    public List<AddressViewModel> Addresses { get; set; }
}

然后,对于列表中的每个条目,应该为AddressViewModel选择一次编辑器模板。您必须添加一些Ajax以允许创建新的地址,就像您的示例链接一样。只要模板包含AddressViewModel工作的所有字段,那么您的Edit POST控制器应该只接收PersonViewModel作为其参数。

我的示例中缺少一些部分,但您应该能够填写教程中的空白。