2012-09-11 66 views
9

Tôi có trang Chỉnh sửa cho ứng dụng MVC của mình, sử dụng Dao cạo.Làm cách nào để tạo Biểu mẫu Chỉnh sửa cho đối tượng có thuộc tính Danh sách trong ASP.NET MVC 4 bằng Dao cạo

Tôi có một mô hình như:

public class MyModelObject 
{ 
    public int Id { get; set; } 

    public string Name { get; set; } 

    public string Description { get; set; } 

    public List<MyOtherModelObject> OtherModelObjects { get; set; } 
} 

Và MyOtherModelObject trông giống như:

public class MyOtherModelObject 
{ 
    public string Name { get; set; } 

    public string Description { get; set; } 
} 

Tôi đang làm cho Chỉnh sửa trang cho MyModelObject. Tôi cần một cách để thêm không gian vào biểu mẫu trên trang Chỉnh sửa cho MyModelObject để người dùng tạo/thêm bao nhiêu trường hợp MyOtherModelObject khi người dùng muốn vào Danh sách OtherModelObjects.

Tôi cho rằng người dùng có thể nhấn nút, sẽ thực hiện hành động khác trả về một phần của các phần tử biểu mẫu (không có thẻ biểu mẫu vì mục đích này là một phần của biểu mẫu trên trang chỉnh sửa của tôi). Khi người dùng đã thêm tất cả MyOtherModelObject mà họ muốn và điền vào dữ liệu, họ sẽ có thể lưu các chỉnh sửa của họ vào MyModelObject hiện tại, điều đó sẽ HttpPost đến hành động Chỉnh sửa và hy vọng rằng tất cả MyOtherModelObjects sẽ nằm trong danh sách chính xác.

Tôi cũng cần người dùng có thể sắp xếp lại các mặt hàng khi họ đã thêm chúng.

Có ai biết cách thực hiện tác phẩm này không? Bạn có dự án mẫu hoặc hướng dẫn mẫu trực tuyến với giải pháp này được triển khai không?

+0

Bạn có thể xem http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx (mặc dù nó cho dù cú pháp Dao cạo, cũng như MVC4 nó có thể có thể cung cấp cho một ý tưởng) –

+0

Thoạt nhìn. Điều đó có vẻ như nó sẽ làm việc cho một danh sách, nhưng nó sẽ làm việc cho một danh sách đó là một phần của đối tượng khác, và nó sẽ có thể ràng buộc các mô hình? – DaveH

Trả lời

19

Điều này blog post chứa hướng dẫn từng bước minh họa cách đạt được điều đó.


UPDATE:

Theo yêu cầu trong phần ý kiến ​​tôi đang minh họa từng bước làm thế nào để thích ứng với bài viết nói trên để kịch bản của mình.

mẫu:

public class MyOtherModelObject 
{ 
    public string Name { get; set; } 
    public string Description { get; set; } 
} 

public class MyModelObject 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Description { get; set; } 
    public List<MyOtherModelObject> OtherModelObjects { get; set; } 
} 

Bộ điều khiển:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     var model = new MyModelObject 
     { 
      Id = 1, 
      Name = "the model", 
      Description = "some desc", 
      OtherModelObjects = new[] 
      { 
       new MyOtherModelObject { Name = "foo", Description = "foo desc" }, 
       new MyOtherModelObject { Name = "bar", Description = "bar desc" }, 
      }.ToList() 
     }; 
     return View(model); 
    } 

    [HttpPost] 
    public ActionResult Index(MyModelObject model) 
    { 
     return Content("Thank you for submitting the form"); 
    } 

    public ActionResult BlankEditorRow() 
    { 
     return PartialView("EditorRow", new MyOtherModelObject()); 
    } 
} 

View (~/Views/Home/Index.cshtml):

@model MyModelObject 

@using(Html.BeginForm()) 
{ 
    @Html.HiddenFor(x => x.Id) 
    <div> 
     @Html.LabelFor(x => x.Name) 
     @Html.EditorFor(x => x.Name) 
    </div> 
    <div> 
     @Html.LabelFor(x => x.Description) 
     @Html.TextBoxFor(x => x.Description) 
    </div> 
    <hr/> 
    <div id="editorRows"> 
     @foreach (var item in Model.OtherModelObjects) 
     { 
      @Html.Partial("EditorRow", item); 
     } 
    </div> 
    @Html.ActionLink("Add another...", "BlankEditorRow", null, new { id = "addItem" }) 

    <input type="submit" value="Finished" /> 
} 

một phần (~/Views/Home/EditorRow.cshtml):

@model MyOtherModelObject 

<div class="editorRow"> 
    @using (Html.BeginCollectionItem("OtherModelObjects")) 
    { 
     <div> 
      @Html.LabelFor(x => x.Name) 
      @Html.EditorFor(x => x.Name) 
     </div> 
     <div> 
      @Html.LabelFor(x => x.Description) 
      @Html.EditorFor(x => x.Description) 
     </div> 
     <a href="#" class="deleteRow">delete</a> 
    } 
</div> 

Script:

$('#addItem').click(function() { 
    $.ajax({ 
     url: this.href, 
     cache: false, 
     success: function (html) { 
      $('#editorRows').append(html); 
     } 
    }); 
    return false; 
}); 

$('a.deleteRow').live('click', function() { 
    $(this).parents('div.editorRow:first').remove(); 
    return false; 
}); 

Ghi chú: các helper BeginCollectionItem tùy chỉnh được lấy từ cùng một điều tôi đã liên kết với, nhưng tôi cung cấp nó ở đây cho đầy đủ lợi ích của câu trả lời:

public static class HtmlPrefixScopeExtensions 
{ 
    private const string idsToReuseKey = "__htmlPrefixScopeExtensions_IdsToReuse_"; 

    public static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName) 
    { 
     var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName); 
     string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : Guid.NewGuid().ToString(); 

     // autocomplete="off" is needed to work around a very annoying Chrome behaviour whereby it reuses old values after the user clicks "Back", which causes the xyz.index and xyz[...] values to get out of sync. 
     html.ViewContext.Writer.WriteLine(string.Format("<input type=\"hidden\" name=\"{0}.index\" autocomplete=\"off\" value=\"{1}\" />", collectionName, html.Encode(itemIndex))); 

     return BeginHtmlFieldPrefixScope(html, string.Format("{0}[{1}]", collectionName, itemIndex)); 
    } 

    public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix) 
    { 
     return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix); 
    } 

    private static Queue<string> GetIdsToReuse(HttpContextBase httpContext, string collectionName) 
    { 
     // We need to use the same sequence of IDs following a server-side validation failure, 
     // otherwise the framework won't render the validation error messages next to each item. 
     string key = idsToReuseKey + collectionName; 
     var queue = (Queue<string>)httpContext.Items[key]; 
     if (queue == null) 
     { 
      httpContext.Items[key] = queue = new Queue<string>(); 
      var previouslyUsedIds = httpContext.Request[collectionName + ".index"]; 
      if (!string.IsNullOrEmpty(previouslyUsedIds)) 
       foreach (string previouslyUsedId in previouslyUsedIds.Split(',')) 
        queue.Enqueue(previouslyUsedId); 
     } 
     return queue; 
    } 

    private class HtmlFieldPrefixScope : IDisposable 
    { 
     private readonly TemplateInfo templateInfo; 
     private readonly string previousHtmlFieldPrefix; 

     public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix) 
     { 
      this.templateInfo = templateInfo; 

      previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix; 
      templateInfo.HtmlFieldPrefix = htmlFieldPrefix; 
     } 

     public void Dispose() 
     { 
      templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix; 
     } 
    } 
} 
+1

Không chính xác. Nó thảo luận cách làm một danh sách các đối tượng có độ dài thay đổi, nhưng nó không thảo luận cách thực hiện nó cho một danh sách độ dài biến của các đối tượng là một phần của một đối tượng khác. – DaveH

+0

@DaveH, nhưng điều đó sẽ dễ dàng thực hiện. Tất cả những gì bạn phải làm là giới thiệu một mô hình khung nhìn mới có thuộc tính 'IEnumerable ' của danh sách bạn đang cố sửa, chính xác như bạn có trong câu hỏi của mình với 'MyModelObject'. –

+1

Thật dễ dàng bạn nói? Và làm thế nào tất cả điều này sẽ liên kết với đối tượng cha mẹ MyModelObject. Có một số phần lớn câu trả lời còn lại để giải quyết, có thể liên quan đến việc viết lại hành vi ModelBind mặc định của MVC. Có những lo ngại về bảo mật khi thực hiện điều này không. Tôi đang làm việc thông qua mẫu này, và tìm thấy nó trên một số bài viết diễn đàn khác để giải quyết danh sách các đối tượng duy nhất, nhưng đã không nhìn thấy mẫu tôi đã giải quyết hiệu quả được nêu ra. – DaveH

0

Tôi đã có thể học bài học trong bài đăng trên blog này http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/ và áp dụng nó cho trường hợp của tôi khi một ModelObject có nhiều thuộc tính, nhiều trong số đó là Danh sách.

Tôi đã sửa đổi tập lệnh của mình phù hợp để làm việc với nhiều danh sách trong một mô hình và sẽ viết blog giải pháp của tôi ngay khi có thể.Nó chắc chắn sẽ phải đợi cho đến sau khi chạy nước rút hiện tại của tôi. Tôi sẽ đăng liên kết khi tôi hoàn thành.

Các vấn đề liên quan