Knockout / JavaScript Ignore Multiclick

时间:2015-10-14 14:29:35

标签: javascript jquery knockout.js asp.net-mvc-5

我在用户多次单击按钮时遇到一些问题,而我想在第一个Ajax请求执行其操作时抑制/忽略点击。例如,如果用户想要将商品添加到他们的购物车,他们会点击添加按钮。如果他们多次单击“添加”按钮,则会因为尝试将重复项插入购物车而抛出PK违规。

所以这里提到了一些可能的解决方案:Prevent a double click on a button with knockout.js 在这里:How to prevent a double-click using jQuery?

但是,我想知道下面的方法是否是另一种可能的解决方案。目前我使用透明" Saving"覆盖整个屏幕的div试图阻止点击,但仍有一些人设法双击。我假设因为他们可以点击比div可以渲染更快。为了解决这个问题,我试图使用全局变量锁定Ajax调用。

按钮

 <a href="#" class="disabled btn btn-default" data-bind="click: $root.AddItemToCart, visible: InCart() == false"><span style="SomeStyles">Add</span></a>

Knockout按下按钮

执行此脚本
 vmProductsIndex.AddItemToCart = function (item) {
      if (!app.ajaxService.inCriticalSection()) {
                    app.ajaxService.criticalSection(true);
                    app.ajaxService.ajaxPostJson("@Url.Action("AddItemToCart", "Products")",
                        ko.mapping.toJSON(item),
                        function (result) {
                            ko.mapping.fromJS(result, vmProductsIndex.CartSummary);
                            item.InCart(true);
                            item.QuantityOriginal(item.Quantity());
                        },
                        function (result) {
                            $("#error-modal").modal();
                        },
                        vmProductsIndex.ModalErrors);
                    app.ajaxService.criticalSection(false);
                }
 }

调用此脚本

(function (app) {
  "use strict";
  var criticalSectionInd = false;
  app.ajaxService = (function () {
      var ajaxPostJson = function (method, jsonIn, callback, errorCallback, errorArray) {
         //Add the item to the cart
        }
    };
    var inCriticalSection = function () {
        if (criticalSectionInd)
            return true;
        else
            return false;
    };

    var criticalSection = function (flag) {
        criticalSectionInd = flag;
    };
    // returns the app.ajaxService object with these functions defined
    return {
        ajaxPostJson: ajaxPostJson,
        ajaxGetJson: ajaxGetJson,
        setAntiForgeryTokenData: setAntiForgeryTokenData,
        inCriticalSection: inCriticalSection,
        criticalSection: criticalSection
    };
  })();
}(app));

问题仍然是我可以垃圾邮件点击按钮并获得主键违规。我不知道这种方法是否有缺陷,Knockout在第一次Ajax调用完成之前还没有足够快速更新按钮的可见绑定,或者每次他们点击按钮时都是新的实例criticalSectionInd已创建,而不是真正充当全局变量。

如果我错了,我将使用其他帖子中提到的方法,只是这种方法似乎更容易实现,而无需重构我的所有按钮来使用jQuery One()特征

1 个答案:

答案 0 :(得分:1)

您应该在回调方法中设置app.ajaxService.criticalSection(false);

现在你在if子句的末尾执行这行代码,而不是在成功或错误回调中执行,所以它在你的ajax调用完成之前执行。

vmProductsIndex.AddItemToCart = function (item) {
  if (!app.ajaxService.inCriticalSection()) {
    app.ajaxService.criticalSection(true);
    app.ajaxService.ajaxPostJson("@Url.Action("AddItemToCart", "Products")",
        ko.mapping.toJSON(item),
        function (result) {
            ko.mapping.fromJS(result, vmProductsIndex.CartSummary);
            item.InCart(true);
            item.QuantityOriginal(item.Quantity());
            app.ajaxService.criticalSection(false);
        },
        function (result) {
            $("#error-modal").modal();
            app.ajaxService.criticalSection(false);
        },
        vmProductsIndex.ModalErrors);

    }
}

你可以使用&#34;禁用&#34;从knockout绑定以防止要触发锚标记的click绑定。

这是一个小片段。只需在操作开始时将标志设置为true,并在执行完成后再将其设置为false。与此同时,禁用绑定会阻止用户执行点击功能。

&#13;
&#13;
function viewModel(){
    var self = this;
    self.disableAnchor = ko.observable(false);
    self.randomList = ko.observableArray();
    self.loading = ko.observable(false);
    
    self.doWork = function(){
        if(self.loading()) return;
        
        self.loading(true);
        setTimeout(function(){
            self.randomList.push("Item " + (self.randomList().length + 1)); 
            self.loading(false);
        }, 1000);
    }
}

ko.applyBindings(new viewModel());
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js"></script>
<a href="#" data-bind="disable: disableAnchor, click: doWork">Click me</a>

<br />

<div data-bind="visible: loading">...Loading...</div>

<br />
<div data-bind="foreach: randomList">
    <div data-bind="text: $data"></div>
</div>
&#13;
&#13;
&#13;