Introduction to MVC 4 06. Action Methods, Edit View, and a Search Feature NTPCUG Dr. Tom Perkins The Edit Link • Run the application • Append /Movies to the URL (browse to the Movies controller) • Hover over the Edit link • Examine the generated URL Hover The Edit link was generated by the Html.ActionLink method in the Views\Movies\Index.cshtml view: @Html.ActionLink("Edit", "Edit", new { id=item.ID }) The ActionLink HtmlHelper • Generates a link to an action method on a controller • Arguments: – 1) Text to render (Edit Me) – 2) Name of action method in controller (Edit) – 3) anonymous object route data (ID=4) Alternative: Pass Parameters Using Query String URL of: http://localhost:xxxxx/Movies/Edit?ID=4 Request sent to Controller: Movies Action Method: Edit Parameter ID: 4 // // GET: /Movies/Edit/5 public ActionResult Edit(int id = 0) { Movie movie = db.Movies.Find(id); if (movie == null) { return HttpNotFound(); } return View(movie); } // // POST: /Movies/Edit/5 HttpPost Attribute Default: Implied [HttpGet] attribute [HttpPost] public ActionResult Edit(Movie movie) { if (ModelState.IsValid) { db.Entry(movie).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); } 2 Edit Actions in the Movies Controller Invoked for GET requests Invoked ONLY for POST requests The HTTPGet Edit Method // // GET: /Movies/Edit/5 public ActionResult Edit(int id = 0) { Movie movie = db.Movies.Find(id); if (movie == null) { return HttpNotFound(); } return View(movie); } 1. 2. 3. 4. movie ID paramter input (default = 0) Entity Framework Find used to look up the movie If movie cant be found, return HttpNotFound() The Model movie object is passed to the view When the Edit View was created, the system scanned the model and generated the markup to edit the fields. The Generated Edit View (Part 1) @model MvcMovie.Models.Movie @{ ViewBag.Title = "Edit"; } <h2>Edit</h2> The View expects that the Model it receives will be of type Movie The Generated Edit View (Part 2) @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Movie</legend> @Html.HiddenFor(model => model.ID) <div class="editor-label"> @Html.LabelFor(model => model.Title) </div> <div class="editor-field"> @Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title) </div> … LabelFor displays the name of the field HtmlEditorFor renders an <input> statement ValidationMessageFor displays validation messages associated with field Run the Application • • • • • Navigate to /Movies URL Click an Edit link View the source for the page Examine the HTML for the Form element Note: Html <input> elements are in a <form> element • Form action attribute is set to post • When Edit button is clicked, data will be posted to the server Server actions when the Save button is clicked and the data is posted: [HttpPost] public ActionResult Edit(Movie movie) { if (ModelState.IsValid) { db.Entry(movie).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); } • • • • • • The values from the Form are transformed into a Movie object by the ASP MVC model binder. The Movie object is passed to the Edit action in the Movies controller. The ModelState.IsValid method determines whether or not the data submitted in the form is OK, the data is saved in the db MovieDBContext instance. The movie data is saved to the database . The user is redirected to the Index action, which displays the data with changes. If form data is invalid, data is redisplayed with error messages created by Html.ValidationMessageFor helpers. Posting Edited Form Data Form Edited Data ModelState.IsValid method Valid data Invalid data sent back to form with error messages and form is redisplayed. Data saved to database Data sent to Index action, data (including changes) is displayed Validation error messages Add a Search Method and View • Objective: allow the user to search for movies by genre or name • Add a SearchIndex action to the controller SearchAction method generates Html form for user to enter genre or name Get Search Values User submits search criteria Search Database Display Results Add a SearchIndex method to the MoviesController class public ActionResult SearchIndex(string searchString) { var movies = from m in db.Movies select m; if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); } return View(movies); } • s => s.Title is a Lambda expression • Used in LINQ queries • LINQ queries not executed when defined or modified (deferred) • Executed when value is used or in ToList() • Execution takes place in View Display the Search form for the User • Create a SearchIndex View: • Right click inside the SearchIndex Method • In the AddView dialog box: – Pass a Movie object to the view – Choose List in the Scaffold Template – Click Add @model IEnumerable<MvcMovie.Models.Movie> @{ ViewBag.Title = "SearchIndex"; } <h2>SearchIndex</h2> <p> @Html.ActionLink("Create New", "Create") </p> <table> <tr> <th> Title </th> <th> ReleaseDate </th> <th> Genre </th> <th> Price </th> <th></th> </tr> The Create View @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Title) </td> <td> @Html.DisplayFor(modelItem => item.ReleaseDate) </td> <td> @Html.DisplayFor(modelItem => item.Genre) </td> <td> @Html.DisplayFor(modelItem => item.Price) </td> <td> @Html.ActionLink("Edit", "Edit", new { id=item.ID }) | @Html.ActionLink("Details", "Details", new { id=item.ID }) | @Html.ActionLink("Delete", "Delete", new { id=item.ID }) </td> </tr> } </table> Run the App • Navigate using /Movies/SearchIndex?searchString=ghost Add a filter <form> @model IEnumerable<MvcMovie.Models.Movie> @{ ViewBag.Title = "SearchIndex"; } <h2>SearchIndex</h2> <p> @Html.ActionLink("Create New", "Create") @using (Html.BeginForm()){ <p> Title: @Html.TextBox("SearchString") <br /> <input type="submit" value="Filter" /></p> } </p> FINIS