(14)使用Ajax 提交 Form表单

问题

你有一个网页,列出重要的信息明细,你要允许用户迅速、轻松提交一个表单,无需重新加载整个页面,失去自己在网站上的位置。

解决方案

使用AjaxHelper,创建一个新的Form,用新提交的内容自动更新现有的内容。

讨论

下边的例子把以前的秘方放在一起,向人们展示如何让用户提交一本书的评论,而不重定向到另一个页面去看那些评论以及自己提交的评论。

首先,我们需要创建一个新的model,用于存储对书的评论。在model文件夹,右键->添加->class,命名为:BookComment.cs。这个模型将用于存储对书的评论。代码如下:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
 
namespace MvcApplication.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,去对这个表添加一个引用。先前的这个类是创建在原始的BookModel上。因此专门创建一个新的文件来存储这个类是明智的选择。因为它将在您的项目中和未来的表一起继续成长。右键点击Models文件夹。再次,选择添加→类。这个类的名称将 BookDBContext:

(译者:不要忘记删除你在Book model里的BookDBContext哦!)

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
 
namespace MvcApplication.Models
{
     public class BookDBContext : DbContext
     {
         public DbSet< Book > Books { get; set; }
         public DbSet< BookComment > BookComments { get; set; }
     }
}
 

下面,重新build你的解决方案,在下边的步骤里你就可以找到我们新创建的model了。

我们要创建一个新的controller去实现 评论列表并且有能力去管理它们。选择controller文件夹,单击“添加”→“控制器,命名为:BookCommentsController.cs。为了是手工工作最小化。我们将使用Entity Framework 脚手架创建controller。对于Data context class,选择刚才创建的BookDBContext。(译者:Modle class 选择:BookComment (MvcApplication.Models))。点击添加。当你再次运行应用程序时,你将接收到一个错误指示出:BookDBContext已经改变了。为了解决这个问题,你必须为DBContext创建一个initializer(初始化器)。因为这不是一个生产环境的应用程序,初始化器将删除和重新创建数据库。为了实现这个,右击Models文件夹。选择添加->class ,命名为BookInitializer,代码如下:

 

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System;
 
using System.Collections.Generic;
 
using System.Data.Entity;
 
using System.Linq;
 
using System.Web;
 
  
 
namespace MvcApplication.Models
 
{
 
         public class BookInitializer : DropCreateDatabaseIfModelChanges< BookDBContext >
 
         {
 
         }
 
}
 

 

接下来Global.asax.cs要被更新,在Application_Start中去调用BookInitializer,更新Application_Start方法如下:

双击代码全选
1
2
3
4
5
6
7
8
protected void Application_Start()
         {
             Database.SetInitializer< BookDBContext >(new BookInitializer());
             AreaRegistration.RegisterAllAreas();
 
             RegisterGlobalFilters(GlobalFilters.Filters);
             RegisterRoutes(RouteTable.Routes);
         }
 

 

配置工作完成了,现在我们要做的就是允许用户通过Ajax提交一个评论。我们将从Book/Details view 开始,因为展现评论的大多数逻辑都在这里。(译者:由于原书中引用代码较多,我只在这指出我们更改的代码)。代码如下:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@model MvcApplication.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>,它里边又包含了一个<div>,div的 id是” Comments”,在这个div中有一个Html.RenderAction(),它可以通过传递一个BookId参数到BookComment controller的Index action。

接下来,我们需要更新BookComments/Index view。在下边的例子里,Create New  link被更新成,通过Ajax替代重定向去展示Form。也会移除一些links,因为我们只需要添加的能力,不需要去管理这些评论。代码如下:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@model IEnumerable< MvcApplication.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 view。将使用Ajax.BeginForm 去替换默认的Html.BeginForm。另外一件事是告诉当Ajax提交完成时,让Form来调用一个JavaScript:函数 ReloadComments()。此函数使用jQuery的Ajax请求来检索更新的评论列表。也要创建一个带BookID的hidden field去替换自动创建的下拉列表。

代码如下:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@model MvcApplication.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更新一些代码:

(译者:作者为嘛总是说最后一步,都多少个最后一步了,别急,马上就完成了 )

 

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplication.Models;
 
namespace MvcApplication.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 Action已更新,接受整数的参数BookID。这被设置到ViewBag。另一个重要变化是,返回一个partial view 替代 返回完整的view(阻止完整的layout显示)。如果你还记得在前面的例子,我们重用了相同的view执行Ajax请求,并在视图中检查,看它是否是一个Ajax请求去禁用layout。因为这个view是只通过Ajax显示,更新controller去返回一个partial view是简单的。 最后,Create action也被更新。基本的Create action就像Index action一样 接收一个BookID,并返回一个partial view。第二,Create函action已被更新去设置评论的创建日期。如果有错误,返回一个partial view。Edit,details和delete action已经被移除了,因为没用到他们。这些View也可以删除,因为他们也没有被使用。 现在,当用户浏览一本书的细节,他们可以看到全部评论 已发布的,如果他们想添加自己的意见,他们可以看到已经评论的列表。如果他们想添加自己的内容,他们可以点击create new link,输入他们的内容,提交,并且自动的看到他们刚提交的内容而不需要离开book详细页。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lin&Yi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值