代码之家  ›  专栏  ›  技术社区  ›  Chris

通过Ajax和模型更新加载ASP.netmvc2自定义模板

  •  2
  • Chris  · 技术社区  · 16 年前

    public ParentViewModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public List<ChildViewModel> Child { get; set; } 
    }
    
    public ChildViewModel
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
    }
    

    在我的一个视图中,我传入一个ParentViewModel作为模型,然后使用

    <%: Html.EditorFor(x => x) %>
    

    显示Id和Name属性的窗体。

    当用户单击一个按钮时,我会通过Ajax调用一个操作,以加载到一个局部视图中,该视图包含一个子视图的集合:

    <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Child>>" %>
    <%: Html.EditorFor(x => x) %>
    

    我遇到的问题是,子自定义模板创建的表单没有使用DefaultModelBinder使用的命名约定。

    ie字段名是(由Ajax加载时):

    [0].FirstName
    

    而不是:

    Child[0].FirstName
    

    因此,我的控制器中的编辑操作:

    [HttpPost]
    public virtual ActionResult Edit(int id, FormCollection formValues)
    {
        ParentViewModel parent = new ParentViewModel();
        UpdateModel(parent);
    
        return View(parent);
    }
    

    从提交的表单重新创建ParentViewModel不起作用。

    我想知道通过Ajax加载自定义模板,然后使用UpdateModel的最佳方法是什么。

    3 回复  |  直到 15 年前
        1
  •  9
  •   WestDiscGolf    16 年前

    首先,您需要记住默认的ModelBinder是递归的,它将尝试并解决它需要做什么。。。太聪明了。另一件要记住的事是你不知道 需要 要使用html助手,实际的html也可以正常工作:-)

    所以,首先是模型,这里没什么不同。。

    public class ParentViewModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public List<ChildViewModel> Child { get; set; }
    }
    
    public class ChildViewModel
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
    }
    

    父局部视图 -这将获取ParentViewModel的一个实例

    <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ParentViewModel>" %>
    
    <h2>Parent</h2>
    <%: Html.TextBox("parent.Name", Model.Name) %>
    <%: Html.Hidden("parent.Id", Model.Id) %>
    
    <% foreach (ChildViewModel childViewModel in Model.Child)
    {
        Html.RenderPartial("Child", childViewModel);         
    }
    %>
    

    子局部视图 -这需要一段时间

    <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ChildViewModel>" %>
    
    <h3>Child</h3>
    <%: Html.Hidden("parent.Child.index", Model.Id) %>
    <%: Html.Hidden(string.Format("parent.Child[{0}].Id", Model.Id), Model.Id)%>
    <%: Html.TextBox(string.Format("parent.Child[{0}].FirstName", Model.Id), Model.FirstName) %>
    

    public ActionResult Index()
    {
        ViewData["Message"] = "Welcome to ASP.NET MVC!";
    
        ViewData["Parent"] = GetData();
    
        return View();
    }
    
    private ParentViewModel GetData()
    {
        var result = new ParentViewModel
                         {
                             Id = 1,
                             Name = "Parent name",
                             Child = new List<ChildViewModel>
                                         {
                                             new ChildViewModel {Id = 2, FirstName = "first child"},
                                             new ChildViewModel {Id = 3, FirstName = "second child"}
                                         }
                         };
        return result;
    }
    

    在现实世界中,你可以调用数据服务等。

    最后是索引视图的内容:

    <form action="<%: Url.Action("Edit") %>" method="post">
        <% if (ViewData["Parent"] != null)  { %>
    
            <%
                Html.RenderPartial("Parent", ViewData["Parent"]); %>
    
        <% } %>
        <input type="submit" />
    </form>
    

    正在保存

    [HttpPost]
    public ActionResult Edit(ParentViewModel parent)
    {
    
    }
    

    这将为您提供原始ID的更新细节(来自隐藏字段),以便您可以根据需要进行更新/编辑。

    通过Ajax的新孩子

    如果是这样,你就这样做。。。

    添加操作 -需要返回新的ChildViewModel的操作

    [HttpPost]
    public ActionResult Add()
        {
            var result = new ChildViewModel();
            result.Id = 4;
            result.FirstName = "** to update **";
            return View("Child", result);
        }
    

    为了便于演示,我给了它一个id。

    然后需要一种调用代码的方法,因此需要更新的唯一视图是主索引视图。这将包括获取操作结果的javascript、调用代码的链接和要附加的HTML的目标HTML标记。另外,不要忘记在母版页或视图顶部添加对jQuery的引用。

    索引视图-已更新!

    <script type="text/javascript">
    
       function add() {
    
            $.ajax(
                {
                    type: "POST",
                    url: "<%: Url.Action("Add", "Home") %>",
                    success: function(result) {
                        $('#newchild').after(result);
                    },
                    error: function(req, status, error) {
    
                    }
            });
        }
    
    </script>
    
    <form action="<%: Url.Action("Edit") %>" method="post">
        <% if (ViewData["Parent"] != null)  { %>
    
            <%
                Html.RenderPartial("Parent", ViewData["Parent"]); %>
    
        <% } %>
        <div id="newchild"></div>
    
        <br /><br />
        <input type="submit" /> <a href="#" onclick="JavaScript:return add();">add child</a>
    </form>
    

    这将调用add操作,并在返回到submit按钮上方的newChild div时追加响应。

    我希望这封长信有用。

        2
  •  2
  •   cRichter    16 年前

    使系统更干净。还有你的回帖;-)

        3
  •  1
  •   Chris    16 年前

    我找到了另一种方法来实现这一点,这在我的特殊情况下是有效的。

    而不是通过强类型化到子集合(如:

    <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Child>>" %>
    

    我为父类型创建了一个强类型视图,然后在列表中调用EditorFor,如下所示:

    <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Parent>" %>
    <%: Html.EditorFor(x => x.ChildList) %>
    

    然后调用一个定制的显示模板,结果是所有的HTML元素都得到了正确的命名,并且默认的模型绑定器可以将所有内容放回一起。