Problem
You have a webpage that lists important information details. You need to allow users to submit a form quickly and easily without re-loading the entire page and losing their location on the website.
Solution
Use AjaxHelper to create a new Form and automatically update the existing content with the newly submitted content.
Discussion
The example below puts the previous recipe together to show people how to ask users to submit comments of a book, instead of redirecting them to another page to view those comments and comments submitted by themselves.
First, we need to create a new model to store comments to books. In the model folder, right-click and choose "add"> "class", and name it BookComment. cs. This model will be used to store comments on books. The Code is as follows:
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 {get; set ;}
}
}
Next, you must update the previously created BookDBContext to add a reference to the table. The previous class was created on the original BookModel. Therefore, it is wise to create a new file to store this class. Because it will continue to grow with the tables in your project and in the future. Right-click the Models folder. Again, select Add> class. The class name will be BookDBContext:
(TRANSLATOR: do not forget to delete your BookDBContext in the Book model !)
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 ;}
}
}
Next, build your solution again. In the following steps, you can find our new model.
We need to create a new controller to implement the comment list and have the ability to manage them. Select the controller folder and click "add"> "controller". Name it BookCommentsController. cs. To minimize manual work. We will use Entity Framework scaffolding to create a controller. For Data context class, select the created BookDBContext. (TRANSLATOR: Modle class selection: BookComment (MvcApplication. Models )). Click Add. When you run the application again, you will receive an error indicating that the BookDBContext has changed. To solve this problem, you must create an initializer for DBContext ). Because this is not a production environment application, the initialization will delete and recreate the database. To achieve this, right-click the Models folder. Select Add> class and name it BookInitializer. The Code is as follows:
Using System;
Using System. Collections. Generic;
Using System. Data. Entity;
Using System. Linq;
Using System. Web;
Namespace MvcApplication. Models
{
Public class BookInitializer: DropCreateDatabaseIfModelChanges <BookDBContext>
{
}
}
Next, Global. asax. cs will be updated. Call BookInitializer in Application_Start. The method for updating Application_Start is as follows:
Protected void Application_Start ()
{
Database. SetInitializer <BookDBContext> (new BookInitializer ());
AreaRegistration. RegisterAllAreas ();
RegisterGlobalFilters (GlobalFilters. Filters );
RegisterRoutes (RouteTable. Routes );
}
Now that the configuration is complete, we need to allow users to submit a comment through Ajax. We will start with Book/Details view, because most of the logic for displaying comments is here. (TRANSLATOR: because the original book references a lot of code, I only pointed out the code we changed here ). The Code is as follows:
@ Model MvcApplication. Models. Book
@{
ViewBag. Title = "Details ";
}
<H2>
Details
<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>
In the above Code, a new <fieldset> is added, which contains a <div>. the id of the div is "Comments", and the div contains an Html. renderAction (), which can be passed to the Index action of the BookComment controller by passing a BookId parameter.
Next, we need to update BookComments/Index view. In the following example, Create New link is updated to display the Form by replacing redirection with Ajax. Some links will also be removed, because we only need to add capabilities and do not need to manage these comments. The Code is as follows:
@ Model IEnumerable <MvcApplication. Models. BookComment>
@{
ViewBag. Title = "Index ";
}
<H2>
Index
<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>
Note that the automatically generated BookComments/Create view must be changed. Use Ajax. BeginForm to replace the default Html. BeginForm. Another thing is to tell the Form to call a JavaScript: function ReloadComments () When Ajax is submitted (). This function uses jQuery's Ajax request to retrieve the updated comment list. Create a hidden field with the BookID to replace the automatically created drop-down list.
The Code is as follows:
@ Model MvcApplication. Models. BookComment
@{
ViewBag. Title = "Create ";
}
<H2>
Create
<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>
}
To complete this example, we also need to update some code in BookCommentsController:
(TRANSLATOR: Why does the author always say the last step? How many are the last steps? Don't worry. It will be done right away)
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 );
}
}
}
In the preceding example, the Index Action has been updated and the BookID parameter of the integer is accepted. This is set to ViewBag. Another important change is to return a partial view instead of returning the complete view (blocking the full layout display ). If you still remember the previous example, we re-use the same view to execute Ajax requests and check in the view to see if it is an Ajax request to disable layout. Because this view is displayed only through Ajax, it is simple to update the controller to return a partial view.
Finally, the Create action is updated. The basic Create action receives a BookID like the Index action and returns a partial view. Second, the Create letter action has been updated to set the comment creation date. If an error occurs, a partial view is returned. Edit, details, and delete actions have been removed because they are useless. These views can also be deleted because they are not used.
Now, when users browse the details of a book, they can see all the comments
If they want to add their own comments, they can see the list of comments that have been posted. If they want to add their own content, they can click create new link, enter their content, submit, and automatically view the content they just submitted without leaving the book details page.
Author technical brother