Joe Cuevas Joe Cuevas - 3 months ago 54
Javascript Question

Bootbox callback form submit not working properly

I'm dynamically creating some forms and I'm using bootbox 4 alongside bootstrap 3 and jquery 3.1.0 in an MVC5 application.

Edit: I updated my project's jquery from 1.10.2 to 3.1.0, still have the same issue below.

Usage: click remove, bootbox confirm removal via modal, and if confirmed, call the .submit() action on the form.

Application Screenshot

The issue: I click on the delete button and it pops up a modal to confirm the action, and i click "continue" but it does nothing. There seems to be only one working submit action among all the form elements. So I'm able to successfully call submit on one element per page refresh.

I'm new to javascript, so I have a basic understanding at the moment and I'm trying figure out what I'm doing wrong with my code below. Any help would be appreciated.

My View code:

@foreach (var user in Model.Users)

{
<tr>
<td>
@user.Id
</td>
<td class="text-center">
@user.FirstName @user.LastName
</td>
<td class="text-center">
@Html.CheckBox("role", user.IsAdmin)
</td>
<td>
@using (Html.BeginForm("UpdateUserRole", "Admin", FormMethod.Post, new {@class = "btn-inline"}))
{
@Html.Hidden("id", user.Id)
@Html.Hidden("role", user.GetRole(user.IsAdmin))
<button type="submit" class="btn btn-info">Update</button>
}
@using (Html.BeginForm("RemoveUser", "Admin", FormMethod.Post, new {@class = "btn-inline", @id=user.Id+"Form"}))
{
@Html.Hidden("id", user.Id)
<button data-user-id=@user.Id type="submit" class="btn btn-danger buttonElement">Remove</button>
}
</td>
</tr>
}


My script (added to bottom of View):

@section scripts
{
<script type="text/javascript">
$(function () {
$('form').on('click','button.buttonElement',function (e) {
var user = $(this).attr("data-user-id");
e.preventDefault();
bootbox.dialog({
message: "Do you want to continue ?", title: "Remove User",
buttons: {
main: { label: "Cancel", className: "btn btn-default", callback: function () { return true; } },
success: { label: "Continue", className: "btn btn-default", callback: function () { $('#'+user+'Form').submit(); } }
}
});
});
});
</script>
}


Edit: Here's some HTML output:

<table class="table table-hover">
<tbody>
<tr>
<td>
Joe
</td>
<td class="text-center">
Joe Cuevas
</td>
<td class="text-center">
<input checked="checked" id="role" name="role" type="checkbox" value="true"><input name="role" type="hidden" value="false">
</td>
<td>
<form action="/Admin/UpdateUserRole" class="btn-inline" method="post">
<input data-val="true" data-val-regex="Invalid!" data-val-regex-pattern="([A-Za-z0-9.-])+" data-val-required="NetworkID is required!" id="id" name="id" type="hidden" value="joe"><input id="role" name="role" type="hidden" value="Admin"> <button type="submit" class="btn btn-info">Update</button>
</form> <form action="/Admin/RemoveUser" class="btn-inline" id="joeForm" method="post">
<input data-val="true" data-val-regex="Invalid!" data-val-regex-pattern="([A-Za-z0-9.-])+" data-val-required="NetwordID is required!" id="id" name="id" type="hidden" value="joe"> <button data-user-id="joe" type="submit" class="btn btn-danger buttonElement">Remove</button>
</form>
</td>
</tr>
</tbody>
</table>


Edit: Solution

It turns out that modelstate was overriding the id value of all forms generated by the foreach loop from my View, on the final HTML output. This explains why all the symptoms above were occurring. I simply added the following code to my controller before returning my viewModel and it was fixed:
ModelState.Remove("id");

Answer

table / tr / td / form is a fine, as far as nesting goes. You can probably simplify triggering the form submit with:

$('form').on('click','button.buttonElement',function (e) {
    var user = $(this).attr("data-user-id");
    var form = $(this).closest('form'); // <-- add this

    e.preventDefault();

    bootbox.dialog({
        message: "Do you want to continue ?", 
        title: "Remove User",
        buttons: {
            main: { 
                label: "Cancel", 
                className: "btn btn-default", 
                callback: function () { 
                    return true; 
                } 
            },
            success: { 
                label: "Continue", 
                className: "btn btn-default", 
                callback: function () { 
                    form.submit();  // <-- change this
                }
            }
         }
    });
 });

You could also simply use the bootbox.confirm function. If you want custom button text, follow the second example here, like so.

$('form').on('click','button.buttonElement',function (e) {
    var user = $(this).attr("data-user-id");
    var form = $(this).closest('form'); // <-- add this

    e.preventDefault();

    bootbox.confirm({
        message: "Do you want to continue ?", 
        title: "Remove User",
        buttons: {
            cancel: { 
                label: "Cancel", 
                className: "btn btn-default"
            },
            confirm: { 
                label: "Continue", 
                className: "btn btn-default"
            }
         },
         callback: function(result) {
             if(result == true) {
                 form.submit();
             }
         }
    });
 });

You might want to consider the fact that a user could trigger the submission of the form without clicking your continue button, in which case the delete request will occur without confirmation.

Also, Bootbox hasn't been confirmed to work with jQuery 3.x yet, although that depends more on the parent Bootstrap library version - you have to upgrade to Bootstrap 3.3.7 if you've upgraded to jQuery 3.x.