[翻译]ASP.NET MVC 3 开发的20个秘诀(十四)[20 Recipes for Programming MVC 3]:使用Ajax提交Form
2011-12-18 20:06
891 查看
议题
当你有一个页面,其中列出重要细节并希望用户可以快速而方便的填写并提交表单,而不需要重新载入整个页面,或在网站上跳转而失去当前导航的页面。
解决方案
使用AjaxHelper类,创建一个使用Ajax提交并自动更新现有内容的新表单。
讨论
下面这个例子与之前的秘诀一起,演示如果允许用户在页面没有刷新的情况下查看评论并提交评论。
首先,创建新的模型用于存储书的评论。右键单击“Models”文件夹,然后选择“添加”→“类”,将其命名为“BookComment.cs”。此模型将用于提交和存储书籍的评论:
接下来,就需要修改BookDBContext必须添加这个表的引用。这个类中已包含之前创建的“Book”模型类。在这个时候,我们需要专门创建一个新文件来存储这个类,因为它会继续增长,可能需要添加你项目中的其他的表。再次右键单击“Models”文件夹,选择“添加”→“类”。将其命名为“BookDBContext”:
这是,需要重新编译应用程序,使新创建的模型在下一步可以被引用。
编译完成后,接下来必须创建一个新的控制器来创建和管理评论信息。右键单击“Controllers”文件夹,选择“添加”→“控制器”。将其命名为“BookCommentsController.cs”。为了减少输入,选择使用实体框架的方式,模型类型,选择新创建的“BookComment”模型类。数据上下文中选择之前创建的“BookDBContext”,选择完毕后,点击“添加”。
当程序下次运行时,会接收到一个错误提示。表明在最后一次使用之后,BookDBContext已经发生改变,我们需要创建一个DBContext初始化方法,这并不是要发布网站,而是在初始化时删除并重新创建数据库。执行此操作,请右键单击“Models”文件夹,并选择“添加”→“类”。将其命名为“BookInitializer.cs”:
接下来,修改Global.asax.cs文件,在Application_Start中调用BookInitializer:
设置工作全部完成,是时候对“Books”文件夹中“Details”视图进行一些修改以允许用户用Ajax提交书籍评论,这也是添加和实现评论最合理的位置:
在上面这个示例中,在书籍细节后面创建了新的<fieldset>标记,在<fieldset>标记中添加新的id为Comments的<div>标记。在这个<div>的Html标记中,执行HTML.RenderAction方法,将当前书籍ID作为参数传回给BookComments的Index方法。
接下来,修改BookComments中的Index视图。在下面示例中,创建的新链接在不刷新页面的情况下,通过Ajax提交并显示表单。当Ajax调用完成,将更新链接下面id为“AddComment”的<div>标记,显示添加评论的表单。在完成的时候,会添加删除评论的链接,当前没有提供管理评论的功能,只能添加评论。
最后,需要修改自动生成的BookComments/Create视图。用Ajax.BeginForm替换Html.BeginForm,另外定义名为ReloadComments的Javascript函数,在Ajax提交完成时调用这个函数。此函数执行了一个JQuery的Ajax请求,检索更新的评论列表。还创建了一个名为“BookId”的表单隐藏项。
完成这个之后,需要对BookCommentsController进行些修改:
在上面的这个例子中,Index方法接受一个名为BookId的整型参数,并赋值给ViewBag。在其他控制器的这个方法中会返回完整的视图内容,但是在这里只返回分布视图的部分(防止显示完整视图)。如果你还记得刚才的例子,你需要在实现Ajax请求完成时,禁用Layout模版功能。但是这个例子通过Ajax获取的仅仅只会返回分布视图的部分。
最后,在完成时需要修改Create方法,第一个Create就像之前Index方法一样接受BookId参数,并返回一个分布视图结果。第二个Create方法会为提交的BookComment对象的Created属性为当前时间,并将评论存储到数据库中并返回一个分布视图。Edit、Details和Delete方法以及它们的视图都可以删除掉了,因为它们都没有使用过。
现在,当用户查看书籍详情时,他们就可以在页面中看到关于书籍的评论或通过点击“Create New“的链接,输入他们的评论内容,点击“提交”,在不刷新页面的情况下提交并看到更新的评论。
参考
原书地址 书籍源代码
当你有一个页面,其中列出重要细节并希望用户可以快速而方便的填写并提交表单,而不需要重新载入整个页面,或在网站上跳转而失去当前导航的页面。
解决方案
使用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>标记中添加新的id为Comments的<div>标记。在这个<div>的Html标记中,执行HTML.RenderAction方法,将当前书籍ID作为参数传回给BookComments的Index方法。
接下来,修改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,另外定义名为ReloadComments的Javascript函数,在Ajax提交完成时调用这个函数。此函数执行了一个JQuery的Ajax请求,检索更新的评论列表。还创建了一个名为“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属性为当前时间,并将评论存储到数据库中并返回一个分布视图。Edit、Details和Delete方法以及它们的视图都可以删除掉了,因为它们都没有使用过。
现在,当用户查看书籍详情时,他们就可以在页面中看到关于书籍的评论或通过点击“Create New“的链接,输入他们的评论内容,点击“提交”,在不刷新页面的情况下提交并看到更新的评论。
参考
原书地址 书籍源代码
相关文章推荐
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十三)[20 Recipes for Programming MVC 3]:实现Ajax增强用户体验
- [翻译]ASP.NET MVC 3 开发的20个秘诀(六)[20 Recipes for Programming MVC 3]:找回忘记的密码
- [翻译]ASP.NET MVC 3 开发的20个秘诀(四)[20 Recipes for Programming MVC 3]:实现多语言支持
- [翻译]ASP.NET MVC 3 开发的20个秘诀(二十)[20 Recipes for Programming MVC 3]:缓存结果数据加速页面载入
- [翻译]ASP.NET MVC 3 开发的20个秘诀(七)[20 Recipes for Programming MVC 3]:对列表进行排序
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十二)[20 Recipes for Programming MVC 3]:缩放图片尺寸创建缩略图
- (转)[翻译]ASP.NET MVC 3 开发的20个秘诀(十八)[20 Recipes for Programming MVC 3]:自动完成搜索
- [翻译]ASP.NET MVC 3 开发的20个秘诀(五)[20 Recipes for Programming MVC 3]:发送欢迎邮件
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十五)[20 Recipes for Programming MVC 3]:启用图片验证码(CAPTCHA)
- [翻译]ASP.NET MVC 3 开发的20个秘诀(三)[20 Recipes for Programming MVC 3]:验证用户输入
- [翻译]ASP.NET MVC 3 开发的20个秘诀(一)[20 Recipes for Programming MVC 3]:通过密码验证限制访问视图
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十)[20 Recipes for Programming MVC 3]:通过关键字进行列表搜索
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十六)[20 Recipes for Programming MVC 3]:站点移动化
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十八)[20 Recipes for Programming MVC 3]:自动完成搜索
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十九)[20 Recipes for Programming MVC 3]:路由用户至特定的Controller或Action
- [翻译]ASP.NET MVC 3 开发的20个秘诀(二十)[20 Recipes for Programming MVC 3]:缓存结果数据加速页面载入
- [翻译]ASP.NET MVC 3 开发的20个秘诀(二)[20 Recipes for Programming MVC 3]:自动生成控制器和视图
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十一)[20 Recipes for Programming MVC 3]:通过表单上传文件
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十七)[20 Recipes for Programming MVC 3]:卷帘式分页加载
- [翻译]ASP.NET MVC 3 开发的20个秘诀(八)[20 Recipes for Programming MVC 3]:对列表进行分页