0

My mark up has one div with id= "divGrid" and one ajax enabled form outside that div. Form contains two text inputs and one submit button with UpdateTargetId = "divGrid". It does update that grid perfectly but add duplicate ajax-enabled form on the page. Why this? How to fix this?

Here is my View:

@model List<EF.Models.Data.Books>

@{
    ViewBag.Title = "CodeFirst";
    Layout = null;
}
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
<div id="divGrid">

        @foreach (var item in Model)
        {
        <table>
            <tr>
                <td>@item.ID</td>
                <td>@item.Name</td>
                <td>@item.Price</td>
                </tr>
            </table>
            }
    </div>
    @using (Ajax.BeginForm(new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "divGrid", InsertionMode = InsertionMode.Replace }))
    {
        @Html.TextBox("name");
        <br />
        @Html.TextBox("price");
        <input type="submit" value="Insert" />    
    }

My controller action:

[HttpPost]
    public ViewResult CodeFirst(FormCollection form)
    {
        book.Name = form["name"];
        book.Price = Convert.ToDecimal(form["price"]);
        context.Books.Add(book);
        context.SaveChanges();
        result = context.Books.ToList();
        return View(result);
    }

Interestingly, my rendered mark-up is something like

<div id="divGrid">
    <div id="divGrid">
    <!-- Data display as expected -->
   </div>
   <!-- ajax enabled form, that is out side of this in source code -->
</div>
<!-- ajax enabled form, that is out side of this in source code -->

enter image description here

2
  • 1
    You need to return a partial view, not a view, and that partial view needs to render just the table data (not the same view you initially rendered) Commented Oct 18, 2015 at 10:22
  • @StephenMuecke thanks, I will try that :) Commented Oct 18, 2015 at 10:24

1 Answer 1

1

Your CodeFirst() method is returning the same view you initially rendered and its being inserted inside the <div id="divGrid"> which is why you see the form repeated. You need to return a separate partial view containing only the table. Create a separate child only method to display the initial table

[ChildActionOnly]
public ActionResult BookTable()
{
  var model = context.Books; // no need for .ToList()
  return PartialView(model);
}

BookTable.cshtml

@model IEnumerable<EF.Models.Data.Books>
@foreach (var item in Model)
{
  <table>
    <tr>
      <td>@item.ID</td>
      <td>@item.Name</td>
      <td>@item.Price</td>
    </tr>
  </table>
}

Then create a view model for adding a new book so you can take advantage of MVC features such as strong type binding, client and server side validation etc.

public class BookVM
{
  [Required]
  public string Name { get; set; }
  public decimal Price { get; set; }
}

and you controller methods become

public ActionResult CodeFirst()
{
  BookVM model = new BookVM();
  return View(model);
}

[HttpPost]
public ViewResult CodeFirst(BookVM model)
{
    Book book = new Book(){ Name = model.Name, Price = model.Price };
    context.Books.Add(book);
    context.SaveChanges();
    result = context.Books();
    return PartialView("BookTable", result);
}

and change your view to

@model BookVM
....
<div id="divGrid">
  @Html.Action("BookTable");
</div>

@using (Ajax.BeginForm(new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "divGrid", InsertionMode = InsertionMode.Replace }))
{
  @Html.LabelFor(m => m.Name)
  @Html.TextBoxFor(m => m.Name)
  @Html.ValidationMessageFor(m => m.Name)
  .... // ditto for Price
  <input type="submit" value="Insert" />    
}

However this means your regenerating the html for the whole table everytime you submit the form. You would get far better performance by just using jquery and ajax to call a method that inserts the book and returns its new ID as json, then dynamically adding a new row to the table based on the returned ID, and the values from the textboxes in the form.

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks for the answer, specially for recommending jquery ajax in this scenario, obviously it be great performance enhancement. just want a little advice, when I am deleting something from table, jquery ajax is better or Ajax.BeginForm ?
jQuery and ajax are far better IMHO. Ajax.BeginForm() just means extra ovehead (loading the script). And you get far more control with the jQuery methods.
so which scenario it's better?
Sorry, not sure what your asking? I'm saying using jQuery and ajax are better than using Ajax.BeginForm().
I am asking which situation Ajax.BeginFor() could be better? if not then what could be the reason razor have it.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.