0

I have recently created a table (Datatables) that relies on a popup window to add entries to it. When you add an item the first time, the modal closes and the table refreshes itself and you can see the new entry. The issue starts when you go and try to add another item to it after the first. Instead of submitting and repeating the early behaviour, it redirects the page to a json output of the html of the modal.

I'm not too sure why and I have also tried to debug it. The second time, it isn't submitting to the controller at all.

This is the jQuery modal I'm using https://github.com/kylefox/jquery-modal

Here is my ajax query to open up a modal with a form

$("#addRole").click(function (e) {
            var form_data = {
                "Id": "@Model.Id",
            };
            $.ajax({
                url: "@Url.Action("NewRole", @ViewContext.RouteData.Values["controller"].ToString())",
                method: "POST",
                data: JSON.stringify(form_data),
                contentType: "application/json",
                success: function (result) {
                    $(result.Output).appendTo('body').modal();
                },
                error: function (error) {
                    console.log(error);
                }
            });
            return false;
        });

This is the div where the form will be attached to

<div id="modal"></div>

The ajax above then goes to this controller function:

    [HttpPost]
    public ActionResult NewRole(String Id)
    {
        var role = new RolesDetailsViewModel
        {
            ApplicationId = Id,
            Id = null,
            RoleName = null
        };
        var result = this.Json(new
        {
            Output = ViewToString.Render(this, "Modal/RoleDetails", role)
        }, JsonRequestBehavior.AllowGet);
        return result;
    }

This controller then returns this modal page

@model ManagementStudio.Data.ViewModels.RolesDetailsViewModel
<div id="roleDetails" class="modal">
    <script>
        $(document).ready(function () {
            $("#form").submit(function (e) {
                e.preventDefault();
                var form_data = $(this).serialize();
                console.log(form_data);
                $.ajax({
                    url: "@Url.Action("SaveRole", @ViewContext.RouteData.Values["controller"].ToString())",
                    method: "POST",
                    data: form_data,
                    contentType: "application/x-www-form-urlencoded; charset=UTF-8",
                    success: function (result) {
                        if (result.success) {
                            console.log("success");
                            $("#close").trigger("click");
                            return;
                        }
                        $.each(result.errors, function (index, item) {
                            // Get message placeholder
                            var element = $('[data-valmsg-for="' + item.propertyName + '"]');
                            // Update message
                            element.append($('<span></span>').text(item.errorMessage));
                            // Update class names
                            element.removeClass('field-validation-valid').addClass('field-validation-error');
                            $('#' + item.propertyName).removeClass('valid').addClass('input-validation-error');
                        });
                    }
                });
                return false;
            });
        });
    </script>
    <div class="col-sm-12">
        @if (Model.Id == null)
        {
            <h2>Add Role</h2>
        }
        else
        {
            <h2>Edit Role</h2>
        }
        <hr />
    </div>
    @using (Html.BeginForm(null,null,FormMethod.Post,new { id="form"}))
    {
        @Html.AntiForgeryToken()
        <div class="col-sm-12">
            <div class="form-group">
                @Html.HiddenFor(m => m.Id)
                @Html.HiddenFor(m => m.ApplicationId)
            </div>
            <div class="form-group">
                @Html.LabelFor(m => m.RoleName)
                @Html.TextBoxFor(m => m.RoleName, new { @class = "form-control col-sm-12" })
                @Html.ValidationMessageFor(m => m.RoleName)
            </div>
            <div class="form-group">
                <div class="clearfix">
                    <input type="submit" id="save" value="Save" class="btn btn-primary pull-right"/>
                    <a href="#" id="close" class="btn btn-default pull-right" rel="modal:close">Cancel</a>
                </div>
            </div>
        </div>
    }
</div>

When I submit the form located on this page, it goes to this controller

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult SaveRole(SaveRolesDetailsViewModel Input)
    {
        if (ModelState.IsValid)
        {
            var result = rolesData.Save(Input);
            if(result == false)
            {
                ModelState.AddModelError("RoleName", "Role Name already exists");
                var errors = AjaxError.Render(this);
                return Json(new { success = false, errors });
            }
            return Json(new { success = true });
        }
        else
        {
            var errors = AjaxError.Render(this);
            return Json(new { success = false, errors });
        }
    }

But the second time I submit the form(without refreshing the page), it doesn't even hit the SaveRole function at all. It just outputs this

{"Output":"\u003cdiv id=\"roleDetails\" class=\"modal\"\u003e\r\n    \u003cscript\u003e\r\n        $(document).ready(function () {\r\n            $(\"#form\").submit(function (e) {\r\n                e.preventDefault();\r\n                var form_data = $(this).serialize();\r\n                console.log(form_data);\r\n                $.ajax({\r\n                    url: \"/Applications/SaveRole\",\r\n                    method: \"POST\",\r\n                    data: form_data,\r\n                    contentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\r\n                    success: function (result) {\r\n                        if (result.success) {\r\n                            console.log(\"success\");\r\n                            $(\"#close\").trigger(\"click\");\r\n                            return;\r\n                        }\r\n                        $.each(result.errors, function (index, item) {\r\n                            // Get message placeholder\r\n                            var element = $(\u0027[data-valmsg-for=\"\u0027 + item.propertyName + \u0027\"]\u0027);\r\n                            // Update message\r\n                            element.append($(\u0027\u003cspan\u003e\u003c/span\u003e\u0027).text(item.errorMessage));\r\n                            // Update class names\r\n                            element.removeClass(\u0027field-validation-valid\u0027).addClass(\u0027field-validation-error\u0027);\r\n                            $(\u0027#\u0027 + item.propertyName).removeClass(\u0027valid\u0027).addClass(\u0027input-validation-error\u0027);\r\n                        });\r\n                    }\r\n                });\r\n                return false;\r\n            });\r\n        });\r\n    \u003c/script\u003e\r\n    \u003cdiv class=\"col-sm-12\"\u003e\r\n            \u003ch2\u003eAdd Role\u003c/h2\u003e\r\n        \u003chr /\u003e\r\n    \u003c/div\u003e\r\n\u003cform action=\"/Applications/NewRole\" id=\"form\" method=\"post\"\u003e\u003cinput name=\"__RequestVerificationToken\" type=\"hidden\" value=\"rKsqdcNvYkjKMs1eGaghb3BTS6ahAK8_1uy3uJ1kKYCewlQN81FMbyMjcxXHjMULnRux5gOkCPjA-C74H2HGeQ7QU29P_EXvlk9HKpAGwAF5U8l6JB25MiJlHZjbb3jLJnvO9hxkopbxEgZDHEc50w2\" /\u003e        \u003cdiv class=\"col-sm-12\"\u003e\r\n            \u003cdiv class=\"form-group\"\u003e\r\n                \u003cinput id=\"Id\" name=\"Id\" type=\"hidden\" value=\"e201adb7-ae20-4ad0-9589-69e9bd903e81\" /\u003e\r\n                \u003cinput id=\"ApplicationId\" name=\"ApplicationId\" type=\"hidden\" value=\"e201adb7-ae20-4ad0-9589-69e9bd903e81\" /\u003e\r\n            \u003c/div\u003e\r\n            \u003cdiv class=\"form-group\"\u003e\r\n                \u003clabel for=\"RoleName\"\u003eRoleName\u003c/label\u003e\r\n                \u003cinput class=\"form-control col-sm-12\" id=\"RoleName\" name=\"RoleName\" type=\"text\" value=\"\" /\u003e\r\n                \u003cspan class=\"field-validation-valid\" data-valmsg-for=\"RoleName\" data-valmsg-replace=\"true\"\u003e\u003c/span\u003e\r\n            \u003c/div\u003e\r\n            \u003cdiv class=\"form-group\"\u003e\r\n                \u003cdiv class=\"clearfix\"\u003e\r\n                    \u003cinput type=\"submit\" id=\"save\" value=\"Save\" class=\"btn btn-primary pull-right\"/\u003e\r\n                    \u003ca href=\"#\" id=\"close\" class=\"btn btn-default pull-right\" rel=\"modal:close\"\u003eCancel\u003c/a\u003e\r\n                \u003c/div\u003e\r\n            \u003c/div\u003e\r\n        \u003c/div\u003e\r\n\u003c/form\u003e\u003c/div\u003e\r\n"}

This is actually the returned code for an empty modal window. I'm not sure what I can do already.

halfer
  • 19,824
  • 17
  • 99
  • 186
JianYA
  • 2,750
  • 8
  • 60
  • 136
  • 1
    Because the `
    ` with `id="form"` that you attached the handler to no longer exists when you replaced to modal. You need to use [Event Delegation](https://learn.jquery.com/events/event-delegation/)
    –  Aug 28 '18 at 05:09
  • Sorry which section do I need to use Event Delegation for? Is it when I submit my form? – JianYA Aug 28 '18 at 05:27
  • 1
    Instead of `$("#form").submit(function (e) {` you need `$(document).on('submit', '#form', function(e) {` (but best to replace `document` with the closest ancestor that exists when the page is first rendered) –  Aug 28 '18 at 05:29
  • Yeah I just changed that in my question to $("#roleDetails").on("submit","#form",function (e) { but its still happening. – JianYA Aug 28 '18 at 05:30
  • 1
    Do not change your code based on comments/answers (I have rolled back your edit). And `the element with `id="roleDetails"` is also being replaced so that is not suitable - it needs to be an element which exists when the page is first rendered and is not replaced –  Aug 28 '18 at 05:34
  • Sorry about that. Does this mean I should take an element from outside the modal window? Seems like everything within the modal with the exception of the div itself gets replaced? – JianYA Aug 28 '18 at 05:36
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/178903/discussion-between-stephen-muecke-and-jianya). –  Aug 28 '18 at 05:37

0 Answers0