简体   繁体   中英

Limit the number of times a button can be pressed - C# ASP.NET MVC5 JavaScript

I have a page that allows you to create Income Types, but if you click the Create button, in succession then it creates multiple entries, Is there a way to have it limit this to you press it once and that is it?

I have looked at the code it uses an ajax method to get the information then post the form to the database. Some of my code below:

Index

@section scripts {
<script language="javascript" type="text/javascript">
    @* DOM ready? *@
    $(function () {
        @* Pagination Async Partial Handling *@
        $(document).on("click", "#indexPager a", function () {
            if ($(this).parent().hasClass('disabled') || $(this).parent().hasClass('active'))
                return false;
            $.ajax({
                url: $(this).attr("href"),
                type: 'GET',
                cache: false,
                success: function (result) {
                    $('#tableContainer').html(result);
                    addBootstrapTooltips("#tableContainer");
                }
            });
            return false;
        });
        $(document).on("change", "#pageSizeSelector", function () {
            var selectedValue = $(this).val();
            $.ajax({
                url: selectedValue,
                type: 'GET',
                cache: false,
                success: function(result) {
                    $('#tableContainer').html(result);
                    addBootstrapTooltips("#tableContainer");
                }
            });
        });

        @* Sorting Async Partial Handling *@
        $(document).on("click", "#tableHeader a", function () {
            $.ajax({
                url: $(this).attr("href"),
                type: 'GET',
                cache: false,
                success: function (result) {
                    $('#tableContainer').html(result);
                    addBootstrapTooltips("#tableContainer");
                }
            });

            return false;
        });

        @* Apply ACTION colours for hover *@
        addTableStylingScripts();
    });
</script>
}

@section additionalStyles {
    @Styles.Render("~/plugins/datatables/media/css/cssDatatables")
}

@section modal {

}

<article class="row">
    <h1 class="pageTitle artistHeader fw200 mb20 mt10">@ViewBag.Title</h1>

    <div class="col-md-12">
        <div class="panel panel-visible" id="tableContainer">
            @Html.Partial("_IncomeTypeManagementList", Model)
        </div>
    </div>
</article>

IncomeTypeManagementList

@* Header *@
<div class="panel-heading createContentTitle">
    <div class="panel-title createLink">
        <a href="@Url.Action("Create", "IncomeTypeManagement", new
            {
                page = Model.PagingInfo.Page,
                take = Model.PagingInfo.Take,
                sortBy = Model.PagingInfo.SortPropertyName,
                sortAsc = Model.PagingInfo.SortAscending
            })" data-container="body" data-toggle="tooltip" title="Add Income Type" id="createIncomeTypeLink">
            <span class="fa fa-file"></span>&nbsp; Add Income Type
        </a>
    </div>
</div>

@* Body *@
<div class="panel-body pn">
    <table class="table table-striped table-hover dataTable incomeTypesTable admin-form theme-primary" cellspacing="0" width="100%" role="grid">
        <thead id="tableHeader">
            <tr>
                <th class="hidden-xs sorting @Html.SortTitleItem("IncomeTypeGroupId", Model.PagingInfo.SortPropertyName, Model.PagingInfo.SortAscending)">
                    <a href="@Url.Action("Index", "IncomeTypeManagement", new
                             {
                                 page = 1,
                                 take = Model.PagingInfo.Take,
                                 sortBy = "IncomeTypeGroupId",
                                 sortAsc = Model.PagingInfo.SortPropertyName != "IncomeTypeGroupId" || !Model.PagingInfo.SortAscending
                             })" data-container="body" data-toggle="tooltip" title="Sort by group">Group</a>
                </th>
                <th class="sorting @Html.SortTitleItem("Name", Model.PagingInfo.SortPropertyName, Model.PagingInfo.SortAscending)">
                    <a href="@Url.Action("Index", "IncomeTypeManagement", new
                             {
                                 page = 1,
                                 take = Model.PagingInfo.Take,
                                 sortBy = "Name",
                                 sortAsc = Model.PagingInfo.SortPropertyName != "Name" || !Model.PagingInfo.SortAscending
                             })" data-container="body" data-toggle="tooltip" title="Sort by name">Name</a>
                </th>
                <th class="hidden-xs sorting hidden-xs @Html.SortTitleItem("CreatedDate", Model.PagingInfo.SortPropertyName, Model.PagingInfo.SortAscending)">
                    <a href="@Url.Action("Index", "IncomeTypeManagement", new
                             {
                                 page = 1,
                                 take = Model.PagingInfo.Take,
                                 sortBy = "CreatedDate",
                                 sortAsc = Model.PagingInfo.SortPropertyName != "CreatedDate" || !Model.PagingInfo.SortAscending
                             })" data-container="body" data-toggle="tooltip" title="Sort by date">Created</a>
                </th>
                <th class="bg-white">
                    <div class="text-center">Action</div>
                </th>
            </tr>
        </thead>
        <tbody>
            @foreach (var it in Model.IncomeTypes)
            {
                var actionId = "action_" + tableRowIndex;
                var editIncomeTypeId = "editIncomeType_" + tableRowIndex;

                <tr data-id="@it.ID"
                    data-isdeleted="@it.IsDeleted"
                    data-rowversion="@it.RowVersion"
                    data-createddate="@it.CreatedDate"
                    data-name="@it.Name"
                    data-incometypegroupid="@it.IncomeTypeGroupId"
                    data-incometypegroupname="@it.IncomeGroupName">
                    <td class="hidden-xs">
                        @it.IncomeGroupName
                    </td>
                    <td>
                        @it.Name.Truncate(50)
                    </td>
                    <td class="hidden-xs">
                        @it.CreatedDate.ToShortDateString()
                    </td>
                    <td class="updateTableRow text-center">
                        <div class="dropdownContainer btn-group text-right">
                            <button type="button" class="btn btn-primary br2 btn-xs fs12 dropdown-toggle" data-toggle="dropdown" aria-expanded="false" id="@actionId">
                                Action
                                <span class="caret ml5"></span>
                            </button>
                            <ul class="dropdown-menu dropdown-menu-right" role="menu">
                                <li>
                                    <a href="@Url.Action("Update", "IncomeTypeManagement", new
                                        {
                                            id = it.ID,
                                            page = Model.PagingInfo.Page,
                                            take = Model.PagingInfo.Take,
                                            sortBy = Model.PagingInfo.SortPropertyName,
                                            sortAsc = Model.PagingInfo.SortAscending
                                        })" data-container="body" data-toggle="tooltip" id="@editIncomeTypeId" title="Edit" data-rowhover="editTableRow">
                                        Edit
                                    </a>
                                </li>
                            </ul>
                        </div>
                    </td>
                </tr>
                tableRowIndex++;
            }
        </tbody>
    </table>
    @Html.Partial("_Pagination", Model.PagingInfo)
</div>

Create

@section scripts {
    @Scripts.Render("~/bundles/jqueryajaxval")
    @Scripts.Render("~/bundles/jqueryval")

    <script language="javascript" type="text/javascript">
        $(document).ready(function () {
            @* Cancel *@
            $(document).on("click", "#CancelForm", function (e) {
                var uri = '@Html.Raw(Url.Action("Index", "IncomeTypeManagement", new 
                { 
                    page = Model.PagingInfo.Page, 
                    take = Model.PagingInfo.Take,
                    sortBy = Model.PagingInfo.SortPropertyName,
                    sortAsc = Model.PagingInfo.SortAscending
                }))';

                window.location = uri;
                    e.preventDefault();
            });
        });
    </script>
}

@section additionalStyles {

}

@section modal {

}

<article class="row">
    <h1 class="pageTitle incomeTypeHeader fw200 mb20 mt10">@ViewBag.Title</h1>

    <div class="col-md-1"></div>
    <div id="incomeTypeResults" class="col-md-10 formContainer">
        <div class="panel">
            <div class="panel-heading">
                <span class="panel-title">
                    <i class="glyphicon glyphicon-pencil"></i>&nbsp;Details Of New Income Type
                </span>
            </div>

            @using (Html.BeginForm("Create",
                                   "IncomeTypeManagement", FormMethod.Post,
                                   new { id = "createIncomeType", role = "form", @class = "theme-primary form-horizontal" }))
            {
                @Html.AntiForgeryToken()

                @* Pagination / Sorting *@
                @Html.HiddenFor(m => m.PagingInfo.Page)
                @Html.HiddenFor(m => m.PagingInfo.Take)
                @Html.HiddenFor(m => m.PagingInfo.SortPropertyName)
                @Html.HiddenFor(m => m.PagingInfo.SortAscending)

                <fieldset>
                    <legend style="display: none">Create Income Type Form</legend>
                    @Html.HiddenFor(m => m.IsDeleted)

                    <div class="panel-body p25 fill bt0">
                        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                        <div class="form-group">
                            @Html.LabelFor(m => m.IncomeTypeGroupId, new { @class = "control-label col-lg-2" })
                            <div class="col-lg-8">
                                @{
                                    // get drop down values for DropDownFor()
                                    var selectableItems = incomeTypeGroups.Select((v, idx) => new SelectListItem
                                    {
                                        Text = v.Value,
                                        Value = v.Key,
                                        Selected = idx == 0
                                    });
                                }
                                @Html.DropDownListFor(m => m.IncomeTypeGroupId, selectableItems, new { @class = "form-control" })
                                @Html.ValidationMessageFor(m => m.IncomeTypeGroupId, string.Empty, new { @class = "text-danger" })
                            </div>
                        </div>

                        <div class="form-group">
                            @Html.LabelFor(m => m.Name, new { @class = "control-label col-lg-2" })
                            <div class="col-lg-8">
                                @Html.TextBoxFor(m => m.Name, new { @class = "form-control", id = "Name", placeholder = "Name..." })
                                @Html.ValidationMessageFor(m => m.Name, string.Empty, new { @class = "text-danger" })
                            </div>
                        </div>
                    </div>

                    <div class="panel-footer">
                        <div class="text-center">
                            <input type="button" class="btn btn-primary" id="CancelForm" value="Cancel" />
                            <input type="submit" class="btn btn-primary" id="SubmitForm" value="Create" />
                        </div>
                    </div>

                </fieldset>
            }
        </div>
    </div>
</article>

Update

section scripts {
    @Scripts.Render("~/bundles/jqueryajaxval")
    @Scripts.Render("~/bundles/jqueryval")

    <script language="javascript" type="text/javascript">
        $(document).ready(function () {
            @* Cancel *@
            $(document).on("click", "#CancelForm", function (e) {
                var uri = '@Html.Raw(Url.Action("Index", "IncomeTypeManagement", new
                {
                    page = Model.PagingInfo.Page,
                    take = Model.PagingInfo.Take,
                    sortBy = Model.PagingInfo.SortPropertyName,
                    sortAsc = Model.PagingInfo.SortAscending
                }))';

                window.location = uri;
                e.preventDefault();
            });
        });
    </script>
}

@section additionalStyles {

}

@section modal {

}

<article class="row">
    <h1 class="pageTitle incomeTypeHeader fw200 mb20 mt10">@ViewBag.Title</h1>

    <div class="col-md-1"></div>
    <div id="incomeTypeResults" class="col-md-10 formContainer">
        <div class="panel">
            <div class="panel-heading">
                <span class="panel-title">
                    <i class="glyphicon glyphicon-pencil"></i>&nbsp;Details Of '@Model.Name'
                </span>
            </div>

            @using (Html.BeginForm("Update",
                                   "IncomeTypeManagement", FormMethod.Post,
                                   new { id = "updateIncomeType", role = "form", @class = "theme-primary form-horizontal" }))
            {
                @Html.AntiForgeryToken()

                @* Pagination / Sorting *@
                @Html.HiddenFor(m => m.PagingInfo.Page)
                @Html.HiddenFor(m => m.PagingInfo.Take)
                @Html.HiddenFor(m => m.PagingInfo.SortPropertyName)
                @Html.HiddenFor(m => m.PagingInfo.SortAscending)


                <fieldset>
                    <legend style="display: none">Edit Income Type Form</legend>
                    @Html.HiddenFor(m => m.ID)
                    @Html.HiddenFor(m => m.RowVersion)
                    @Html.HiddenFor(m => m.IsDeleted)

                    <div class="panel-body p25 fill bt0">
                        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                        <div class="form-group">
                            @Html.LabelFor(m => m.IncomeTypeGroupId, new { @class = "control-label col-lg-2" })
                            <div class="col-lg-8">
                                @{
                                    // get drop down values for DropDownFor()
                                    var selectableItems = incomeTypeGroups.Select((v, idx) => new SelectListItem
                                    {
                                        Text = v.Value,
                                        Value = v.Key,
                                        Selected = Model.IncomeTypeGroupId.ToString() == v.Key
                                    });
                                }
                                @Html.DropDownListFor(m => m.IncomeTypeGroupId, selectableItems, new { @class = "form-control" })
                                @Html.ValidationMessageFor(m => m.IncomeTypeGroupId, string.Empty, new { @class = "text-danger" })
                            </div>
                        </div>

                        <div class="form-group">
                            @Html.LabelFor(m => m.Name, new { @class = "control-label col-lg-2" })
                            <div class="col-lg-8">
                                @Html.TextBoxFor(m => m.Name, new { @class = "form-control", id = "Name", placeholder = "Name..." })
                                @Html.ValidationMessageFor(m => m.Name, string.Empty, new { @class = "text-danger" })
                            </div>
                        </div>
                    </div>

                    <div class="panel-footer">
                        <div class="text-center">
                            <input type="button" class="btn btn-primary" onclick="this.disabled = true" id="CancelForm" value="Cancel" />
                            <input type="submit" class="btn btn-primary" id="SubmitForm" value="Update" />
                        </div>
                    </div>

                </fieldset>
            }
        </div>
    </div>
</article>

So I have tried adding <input type="submit" class="btn btn-primary" id="SubmitForm" value="Update" onclick="this.disabled = true" />

On the Create page When you click on Add Income Tye you are directed to the Create page, but when I have tied testing it the button is disabled, but then it does not submit anything and just remains on the Create page

To answer your question you kind of have to tackle the problem from 2 angles:

  1. once click happens on your button you can either disable it or show an overlay so that no other elements on the page can be interacted with
  2. you also have to think of what happens if some malicious user replays that request multiple times (by bypassing or altering the UI - which is dead easy to do) - on the server side you can use a processing queue of requests and every time you want to add a new request for processing, you can check to see if a duplicate exists

Unfortunately there isn't an easy answer for this. The 2nd part of the answer you have to think about it and assess if you're exposed to this issue. If your application is public and anyone can access it, don't assume that users will do everything on your system just via the UI.

Hope this helps.

This is what I come up with:

<script language="javascript" type="text/javascript">
        $('.form-disable').on('submit', function () {
            var self = $(this),
                button = self.find('input[type="submit"], button'),
                submitValue = button.data('submit-value');
            button.attr('disabled', 'disabled').val((submitValue) ? submitValue : 'Please Wait...');
        });
</script>

I added a class to the form so that when you click on a button that handles the submit, it disables the button and then waits with a message. But it only allows the button to be clicked once.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM