2

Hi I'm new to MVC so please bear with me.

I'm trying to do a simple ajax form that just accepts inserts and lets the user know the record has been saved off into a DB.

My problem is two fold.

  1. The data is being inserted into the DB twice

  2. The editors don't get cleared and the message isn't displayed.

I can get this working using straight HTML form posts but wanted to use ajax and then introduce some sort of loading gif or use spin.js.

my code:

_Layout.cshtml

 <!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    @Styles.Render("~/Content/css")
    @Styles.Render("~/Content/kendo")
    @Scripts.Render("~/bundles/modernizr")
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/kendo")
    @Scripts.Render("~/bundles/jqueryval")

</head>
<body>
    <div id="wrapper" style="width:100%; text-align:center">
        <img src="~/Content/Header.PNG" alt="MyHeader" />
   </div>
    @RenderBody()


    @RenderSection("scripts", required: false)
</body>
</html>

AboutController

 public class AboutController : Controller 
    {
        private readonly IMailRepository repository;

        public AboutController(IMailRepository repo)
        {
            repository = repo;
        }

        public ActionResult AboutUs()
        {
            return View();
        }

        public ActionResult CreateMailing()
        {
            return View(new MailRequest());
        }

        [HttpPost]
        public PartialViewResult CreateMailing(MailRequest model)
        {
            if (model == null)
            {
                return PartialView("_MailingData",new MailRequest());
            }
            if (ModelState.IsValid)
            {
                repository.SaveMailRequest(model);
                ModelState.Clear();
                TempData["message"] = string.Format("{0} has been added to the mailing list.", model.Email);
                return PartialView("_MailingData",new MailRequest());
            }
            else
            {
                return PartialView("_MailingData",model);
            }
        }

    }

_MailingDate.cshtml

 @model MyProj.Models.MailRequest

@Html.EditorForModel()
            <br/>
            <input type="submit" value="Save"/>

            <input type="button" value="Cancel"
                   onclick="location.href='@Url.Action("AboutUs", "About")' " />
            @if (TempData["message"] != null)
             {
                 <div>@TempData["message"]</div>
             }

CreateMailing.cshtml

 @model MyProj.Models.MailRequest

@{
    ViewBag.Title = "Mailing List";
    AjaxOptions ajaxOpts = new AjaxOptions
    {
        InsertionMode = InsertionMode.Replace,
        UpdateTargetId = "ajaxreplace"
    };
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Mailing List Request</title>
</head>
<body>
    <div id="ajaxrequest">
        @using (Ajax.BeginForm(ajaxOpts))
        {
            @Html.Partial("_MailingData")
        }
    </div>
</body>
</html>

----UPDATE

Here is my BundleConfig.cs

 public static class BundleConfig
    {
        // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725
        public static void RegisterBundles(BundleCollection bundles)
        {
            if (bundles == null) return;
            // The jQuery bundle
            bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                "~/Scripts/jquery-{version}.js"));
            //bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
            //    "~/Scripts/jquery-{version}.js",
            //    "~/Scripts/jquery-migrate-1.1.1.js"));


            bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
                        "~/Scripts/jquery-ui-{version}.js"));

            bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                        "~/Scripts/jquery.unobtrusive*",
                        "~/Scripts/jquery.validate*"));


            // The Kendo JavaScript bundle
            bundles.Add(new ScriptBundle("~/bundles/kendo").Include(
                "~/Scripts/kendo.all.min.js",
                // or kendo.all.min.js if you want to use Kendo UI Web and Kendo UI DataViz
                "~/Scripts/kendo.aspnetmvc.min.js"));


            bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));

            bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
                        "~/Content/themes/base/jquery.ui.core.css",
                        "~/Content/themes/base/jquery.ui.resizable.css",
                        "~/Content/themes/base/jquery.ui.selectable.css",
                        "~/Content/themes/base/jquery.ui.accordion.css",
                        "~/Content/themes/base/jquery.ui.autocomplete.css",
                        "~/Content/themes/base/jquery.ui.button.css",
                        "~/Content/themes/base/jquery.ui.dialog.css",
                        "~/Content/themes/base/jquery.ui.slider.css",
                        "~/Content/themes/base/jquery.ui.tabs.css",
                        "~/Content/themes/base/jquery.ui.datepicker.css",
                        "~/Content/themes/base/jquery.ui.progressbar.css",
                        "~/Content/themes/base/jquery.ui.theme.css"));

            // The Kendo CSS bundle
            bundles.Add(new StyleBundle("~/Content/kendo").Include(
                "~/Content/kendo.common.*",
                "~/Content/kendo.uniform.*"));


            // Clear all items from the ignore list to allow minified CSS and JavaScript files in debug mode
            bundles.IgnoreList.Clear();


            // Add back the default ignore list rules sans the ones which affect minified files and debug mode
            bundles.IgnoreList.Ignore("*.intellisense.js");
            bundles.IgnoreList.Ignore("*-vsdoc.js");
            bundles.IgnoreList.Ignore("*.debug.js", OptimizationMode.WhenEnabled);
        }


    }

I think my DB issue may have something to do with the fact I end up with the following in the html of my page

    <script src="/bundles/modernizr"></script>

    <script src="/Scripts/jquery-2.0.0.js"></script>
<script src="/Scripts/jquery-2.0.3.js"></script>

    <script src="/Scripts/kendo.all.min.js"></script>
<script src="/Scripts/kendo.aspnetmvc.min.js"></script>

    <script src="/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="/Scripts/jquery.unobtrusive-ajax.min.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.min.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js"></script>

I'm guessing I shouldn't have both the full and min js scripts registered but am not sure the best way to prevent this whilst still using bundles

My EFMailRepository

public class EFMailRepository : IMailRepository, IDisposable
    {
        private EFDbContext context = new EFDbContext();


        public void SaveMailRequest(MailRequest mailRequest)
        {
            context.MailingList.Add(mailRequest);
            context.SaveChanges();
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                // dispose managed resources
                context.Dispose();
            }
            // free native resources
        }


        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
Mark Sayer
  • 41
  • 4
  • 1
    This looks way to much to [simply reproduce the issue](http://sscce.org/). – Grant Thomas Sep 05 '13 at 16:00
  • First recommendation would be to use `Html.beginform` instead of `Ajax.BeginForm`, and then Ajaxify the form with jquery, have a look at that [here](http://stackoverflow.com/questions/5410055/using-ajax-beginform-with-asp-net-mvc-3-razor) (it's MVC 3, but it works the same), also quick question : I don't see the element with the `ajaxreplace` id in your view, where is it ? – Simon Rapilly Sep 05 '13 at 16:05
  • Why would you recommend the use of jquery's ajax rather than `Ajax.BeginForm`? – WannaCSharp Sep 05 '13 at 16:08

1 Answers1

1

You forgot to put an #ajaxreplace div around the partial:

<div id="ajaxrequest">
    @using (Ajax.BeginForm(ajaxOpts))
    {
        <div id="ajaxreplace">
            @Html.Partial("_MailingData")
        </div>
    }
</div>

You have used this id in your AjaxOptions so you should have a corresponding element in your DOM that will get updated by the result of the AJAX request:

AjaxOptions ajaxOpts = new AjaxOptions
{
    InsertionMode = InsertionMode.Replace,
    UpdateTargetId = "ajaxreplace"
};

As far as your first question about the data being inserted twice into the database is concerned, you haven't provided enough details about your DAL layer so that we could be able to further diagnose the issue. Maybe there's something wrong with your repository.SaveMailRequest method.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Thanks heaps, that worked!! I've updated my post regarding the double DB entries. Any ideas??? – Mark Sayer Sep 06 '13 at 09:11
  • Why did you included all the scripts twice? You should only include them once. If you include them twice you might get 2 AJAX calls. It's a complete mess in your script inclusions. For example you have 2 different versions of jQuery included which cannot work. Keep only the `.min.js` versions. Also nowhere in your code I cannot see the `repository.SaveMailRequest` method implementation. – Darin Dimitrov Sep 06 '13 at 09:11
  • I've updated the post to include the **bold**SaveMailRequest method. The scripts bundle registration (as far as the unobtrusive & validate .js go) come from the vs2012 basic MVC4 template. I'll strip out all the non .min.js scripts that have a min version from my scripts folder and try that – Mark Sayer Sep 06 '13 at 09:48
  • Thank you so so much Darin, that seems to have resolved it. From now on, the first thing I'll do when creating new projects from the basic template is strip out all the non min.js. I think I managed to get two versions of jquery in there whilst attempting to get a third party control working. have tidied that up too. Many thanks again. – Mark Sayer Sep 06 '13 at 10:05