zoukankan      html  css  js  c++  java
  • [翻译]ASP.NET MVC 3 开发的20个秘诀(十四)[20 Recipes for Programming MVC 3]:使用Ajax提交Form

    议题

    当你有一个页面,其中列出重要细节并希望用户可以快速而方便的填写并提交表单,而不需要重新载入整个页面,或在网站上跳转而失去当前导航的页面。

     

    解决方案

    使用AjaxHelper类,创建一个使用Ajax提交并自动更新现有内容的新表单。

     

    讨论

    下面这个例子与之前的秘诀一起,演示如果允许用户在页面没有刷新的情况下查看评论并提交评论。

     

    首先,创建新的模型用于存储书的评论。右键单击“Models”文件夹,然后选择“添加”“类”,将其命名为“BookComment.cs”。此模型将用于提交和存储书籍的评论:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.ComponentModel.DataAnnotations;

    namespace MvcApplication4.Models
    {
    public class BookComment
    {
    public int ID { get; set; }
    [Required]
    public string Comment { get; set; }
    public DateTime Created { get; set; }
    public int BookId { get; set; }
    public virtual Book Book { get; set; }
    }
    }

    接下来,就需要修改BookDBContext必须添加这个表的引用。这个类中已包含之前创建的“Book”模型类。在这个时候,我们需要专门创建一个新文件来存储这个类,因为它会继续增长,可能需要添加你项目中的其他的表。再次右键单击“Models”文件夹,选择“添加”“类”。将其命名为“BookDBContext”:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Data.Entity;

    namespace MvcApplication4.Models
    {
    public class BookDBContext : DbContext
    {
    public DbSet<Book> Books { get; set; }
    public DbSet<BookComment> BookComments { get; set; }
    }
    }

    这是,需要重新编译应用程序,使新创建的模型在下一步可以被引用。

     

    编译完成后,接下来必须创建一个新的控制器来创建和管理评论信息。右键单击“Controllers”文件夹,选择“添加”“控制器”。将其命名为“BookCommentsController.cs”。为了减少输入,选择使用实体框架的方式,模型类型,选择新创建的“BookComment”模型类。数据上下文中选择之前创建的“BookDBContext”,选择完毕后,点击“添加”。

     

    当程序下次运行时,会接收到一个错误提示。表明在最后一次使用之后,BookDBContext已经发生改变,我们需要创建一个DBContext初始化方法,这并不是要发布网站,而是在初始化时删除并重新创建数据库。执行此操作,请右键单击“Models”文件夹,并选择“添加”“类”。将其命名为“BookInitializer.cs”:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Data.Entity;

    namespace MvcApplication4.Models
    {
    public class BookInitializer :
    DropCreateDatabaseIfModelChanges<BookDBContext>
    {
    }
    }

    接下来,修改Global.asax.cs文件,在Application_Start中调用BookInitializer

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using MvcApplication4.Models;
    using System.Data.Entity;
    using System.Globalization;
    using System.Threading;

    namespace MvcApplication4
    {
    public class MvcApplication :
    System.Web.HttpApplication
    {
    ...
    protected void Application_Start()
    {
    Database.SetInitializer<BookDBContext>(new BookInitializer());
    ...
    }
    ...
    }
    }

     

    设置工作全部完成,是时候对“Books”文件夹中“Details”视图进行一些修改以允许用户用Ajax提交书籍评论,这也是添加和实现评论最合理的位置:

    @model MvcApplication4.Models.Book
    @{
    ViewBag.Title = "Details";
    }
    <h2>Details</h2>
    <fieldset>
    <legend>Book</legend>
    <div class="display-label">Title</div>
    <div class="display-field">
    @Html.DisplayFor(model => model.Title)
    </div>
    <div class="display-label">Isbn</div>
    <div class="display-field">
    @Html.DisplayFor(model => model.Isbn)
    </div>
    <div class="display-label">Summary</div>
    <div class="display-field">
    @Html.DisplayFor(model => model.Summary)
    </div>
    <div class="display-label">Author</div>
    <div class="display-field">
    @Html.DisplayFor(model => model.Author)
    </div>
    <div class="display-label">Thumbnail</div>
    <div class="display-field">
    @Html.DisplayFor(model => model.Thumbnail)
    </div>
    <div class="display-label">Price</div>
    <div class="display-field">
    @Html.DisplayFor(model => model.Price)
    </div>
    <div class="display-label">Published</div>
    <div class="display-field">
    @Html.DisplayFor(model => model.Published)
    </div>
    </fieldset>
    <fieldset>
    <legend>Comments</legend>
    <div id="Comments">
    @{Html.RenderAction("Index", "BookComments",
    new { BookId = Model.ID });}
    </div>
    </fieldset>
    <p>
    @Html.ActionLink("Edit", "Edit", new { id=Model.ID }) |
    @Html.ActionLink("Back to List", "Index")
    </p>

     

    在上面这个示例中,在书籍细节后面创建了新的<fieldset>标记,在<fieldset>标记中添加新的idComments<div>标记。在这个<div>Html标记中,执行HTML.RenderAction方法,将当前书籍ID作为参数传回给BookCommentsIndex方法。

     

    接下来,修改BookComments中的Index视图。在下面示例中,创建的新链接在不刷新页面的情况下,通过Ajax提交并显示表单。当Ajax调用完成,将更新链接下面id为“AddComment”的<div>标记,显示添加评论的表单。在完成的时候,会添加删除评论的链接,当前没有提供管理评论的功能,只能添加评论。

    @model IEnumerable<MvcApplication4.Models.BookComment>
    @{
    ViewBag.Title = "Index";
    }
    <h2>Index</h2>
    <p>
    @Ajax.ActionLink("Create New", "Create", new {
    BookId = ViewBag.BookId },
    new AjaxOptions { UpdateTargetId = "AddComment" })
    </p>
    <div id="AddComment"></div>
    <table>
    <tr>
    <th>
    Comment
    </th>
    <th>
    Created
    </th>
    </tr>
    @foreach (var item in Model) {
    <tr>
    <td>
    @Html.DisplayFor(modelItem => item.Comment)
    </td>
    <td>
    @Html.DisplayFor(modelItem => item.Created)
    </td>
    <td>
    @Html.DisplayFor(modelItem => item.Book.Title)
    </td>
    </tr>
    }

    </table>

    最后,需要修改自动生成的BookComments/Create视图。用Ajax.BeginForm替换Html.BeginForm,另外定义名为ReloadCommentsJavascript函数,在Ajax提交完成时调用这个函数。此函数执行了一个JQueryAjax请求,检索更新的评论列表。还创建了一个名为“BookId”的表单隐藏项。

    @model MvcApplication4.Models.BookComment
    @{
    ViewBag.Title = "Create";
    }

    <h2>Create</h2>
    <script src="@Url.Content("~/Scripts/jquery.validate.min.js")"
    type
    ="text/javascript"></script>
    <script src="
    @Url.Content("
    ~/Scripts/jquery.validate.unobtrusive.min.js")"
    type
    ="text/javascript"></script>
    <script type="text/javascript">
    function ReloadComments() {
    $(
    "#Comments").load("@Url.Content(
    "~/BookComments/Index?BookId=" + ViewBag.BookId)");
    }
    </script>
    @using (Ajax.BeginForm(new AjaxOptions {
    OnComplete="ReloadComments()" }))
    {
    @Html.Hidden("BookId", (int)ViewBag.BookId);
    @Html.ValidationSummary(true)
    <fieldset>
    <legend>BookComment</legend>
    <div class="editor-label">
    @Html.LabelFor(model => model.Comment)
    </div>
    <div class="editor-field">
    @Html.EditorFor(model => model.Comment)
    @Html.ValidationMessageFor(model => model.Comment)
    </div>
    <p>
    <input type="submit" value="Create" />
    </p>
    </fieldset>

    }

    完成这个之后,需要对BookCommentsController进行些修改:

     

    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.Entity;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using MvcApplication4.Models;

    namespace MvcApplication4.Controllers
    {
    public class BookCommentsController : Controller
    {
    private BookDBContext db = new BookDBContext();
    //
    // GET: /BookComments/
    public ActionResult Index(int BookId)
    {
    ViewBag.BookId = BookId;
    var bookcomments = db.BookComments.Include(
    b => b.Book).Where(b => b.BookId == BookId);
    return PartialView(bookcomments.ToList());
    }

    //
    // GET: /BookComments/Create
    public ActionResult Create(int BookId)
    {
    ViewBag.BookId = BookId;
    return PartialView();
    }

    //
    // POST: /BookComments/Create
    [HttpPost]
    public ActionResult Create(BookComment bookcomment)
    {
    if (ModelState.IsValid)
    {
    bookcomment.Created = DateTime.Now;
    db.BookComments.Add(bookcomment);
    db.SaveChanges();
    }
    ViewBag.BookId = bookcomment.BookId;
    return PartialView(bookcomment);
    }
    protected override void Dispose(bool disposing)
    {
    db.Dispose();
    base.Dispose(disposing);
    }
    }
    }

    在上面的这个例子中,Index方法接受一个名为BookId的整型参数,并赋值给ViewBag。在其他控制器的这个方法中会返回完整的视图内容,但是在这里只返回分布视图的部分(防止显示完整视图)。如果你还记得刚才的例子,你需要在实现Ajax请求完成时,禁用Layout模版功能。但是这个例子通过Ajax获取的仅仅只会返回分布视图的部分。

     

    最后,在完成时需要修改Create方法,第一个Create就像之前Index方法一样接受BookId参数,并返回一个分布视图结果。第二个Create方法会为提交的BookComment对象的Created属性为当前时间,并将评论存储到数据库中并返回一个分布视图。EditDetailsDelete方法以及它们的视图都可以删除掉了,因为它们都没有使用过。

     

    现在,当用户查看书籍详情时,他们就可以在页面中看到关于书籍的评论或通过点击“Create New“的链接,输入他们的评论内容,点击“提交”,在不刷新页面的情况下提交并看到更新的评论。

     

    参考

    原书地址 书籍源代码

  • 相关阅读:
    思科完成收买Pari Networks 增强智能办事
    天音控股拟与外企协作
    运营商竞速搭建手机支出公司
    C版iPhone 4入华期近 高性价比将引追逐
    诺基亚否认将中断塞班办事
    联通守旧国际遨游短信提醒
    思科宣布揭晓已完成收买Pari Networks的买卖
    各种“Phone”辈出 购置裸机或更划算
    台湾运营商看好中低端智能机加大推销量
    诺基亚Ovi商店开卖《水果忍者》
  • 原文地址:https://www.cnblogs.com/o2ds/p/2291999.html
Copyright © 2011-2022 走看看