【问题标题】:Avoid form multiple submissions and re-enable when done避免表单多次提交并在完成后重新启用
【发布时间】:2011-05-12 20:19:29
【问题描述】:

我有一个表单,它允许根据按下的提交按钮查看页面中的数据或以 csv 格式下载数据。

由于它是一个 long 数据库查询,我希望避免用户多次提交(你知道用户的食指在鼠标左键上的重量.. .) 避免数据库过载,也让用户更放松...

我编写了这个小 jQuery 代码,用 Processing, please wait 和经典的动画旋转 gif 代替提交按钮

$(document).ready(function(){
    //preload wait img
    var $waitImg = $('<img />').attr('src', '/img/wait.gif')
    $('.wait').click(function(){
        $(':submit').hide();
        $(this).after($('<span>Processing, please wait...</span>').prepend($waitImg));
    });
});

一切正常,但有一些缺点:

  • 当用户看到结果然后按下浏览器的后退按钮时,他将再次获得正在处理,请稍候语句并且没有提交按钮(如果他只是想编辑某些内容并进行新查询怎么办)
  • 在提示用户下载 CSV 文件后,他一直被告知要等待...

解决方案可能是检测用户回来或下载盯着或以其他方式告诉他工作正在进行中。

越简单越好。

【问题讨论】:

    标签: javascript jquery


    【解决方案1】:

    当用户看到结果然后按下浏览器的返回按钮时,他将再次得到处理,请等待句子并且没有提交按钮(如果他只是想编辑某些内容并进行新的查询怎么办)

    浏览器正在缓存页面。您可以尝试重置值/删除 $(document).ready() 中的加载图像,当用户使用 onunload 技巧按下后退按钮时应该触发:Is there a cross-browser onload event when clicking the back button?

    在提示用户下载 CSV 文件后,他一直被告知要等待...

    如果没有服务器的帮助,将无法检测到这一点。最简单的做法是通过 ajax “ping”服务器,服务器将告诉客户端下载是否已启动/发送给用户。这可以通过可重复性每 3 秒调用一次服务器来查看下载是否已启动,如果是,则重置/隐藏加载图像和文本。

    您可以使用 jQuery deferred 来帮助使这变得简单且语法优美。

    jQuery

    ​​>
    function downloadStarted()
    {
      var $def = $.Deferred();
    
      var check = function() {
         $.get('/ajax/check-download-status', function(response) {
            if (response.started)
            {
              $def.resolve();
            }
            else
            {
              //Check again in 3 seconds
              setTimeout(check, 3000);
            }
          }, 'json');
      };
        
      check();
    
      return $def.promise();
    }
    

    用法:

    var success = function() { /* reset/hide loading image */ }
    $.when(downloadStarted()).then(success);
    

    PHP/服务器端

    在服务器端 ajax/check-download-status 将如下所示:

    session_start();
    $json['started'] = 0;
    if ($_SESSION['download_started']) $json['started'] = 1;
    return json_encode($json);
    

    显然,当您的 csv 文件发送到客户端时,请将 $_SESSION['download_started'] 设置为 1。

    【讨论】:

    【解决方案2】:

    找到这个:

    Detecting the File Download Dialog In the Browser

    这是我基于它的代码:

    html

    <form ...> 
        <fieldset> 
        ...
        <div> 
            <input class="wait" id="submit" name="submit" type="submit" value="View" /> 
            <input class="wait" id="submit" name="submit" type="submit" value="Download as CSV" /> 
        </div> 
        </fieldset> 
    </form> 
    

    javascript

    $(document).ready(function(){
        var cookieCheckTimer;
        var cookieName = 'download_token';
        var $wait = $('.wait');
        var $waitMsg = $('<span>Processing, please wait...</span>').prepend(
            $('<img />').attr('src', '/img/wait.gif').css({
                'vertical-align': 'middle',
                'margin-right': '1em'
            }));
        //add hidden field to forms with .wait submit
        $wait.parent().each(function(){
            $(this).append($('<input />').attr({
                'type': 'hidden',
                'name': cookieName,
                'id': cookieName
            }));
        });
        $wait.click(function(){
            var token = new Date().getTime();
            //set token value
            $('#' + cookieName).val(token);
            //hide submit buttons
            $(':submit').hide();
            //append wait msg
            $(this).after($waitMsg);
    
            cookieCheckTimer = window.setInterval(function () {
                if ($.cookie(cookieName) == token){
                    //clear timer
                    window.clearInterval(cookieCheckTimer);
                    //clear cookie value
                    $.cookie(cookieName, null);
                    //detach wait msg
                    $waitMsg.detach();
                    //show again submit buttons
                    $(':submit').show();
                }
            }, 1000);
        });
    });
    

    服务器端如果在请求参数中找到 download_token 键,则会设置一个带有其名称和值的 cookie。

    这是我用于控制器 __before__ 的 python (pylons) 代码:

    蟒蛇

    cookieName = 'download_token'
    #set file download coockie if asked
    if cookieName in request.params:
        response.set_cookie(cookieName,
            #str: see http://groups.google.com/group/pylons-discuss/browse_thread/thread/7d42f3b28bc6f447
            str(request.params.get(self._downloadTokenName)),
            expires=datetime.now() + timedelta(minutes=15))
    

    我将cookie过期时间设置为15分钟以不填满客户端cookie,您可以根据任务所需的时间选择合适的持续时间。

    这也适用于浏览器返回按钮问题,因为返回时会找到 cookie 并恢复按钮。

    【讨论】:

      猜你喜欢
      • 2014-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多