避免表单多个提交,并在完成后重新启用

Avoid form multiple submissions and re-enable when done

本文关键字:新启用 启用 表单 提交      更新时间:2023-09-26

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

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

我写了这个小jQuery代码来替换提交按钮与处理,请稍候和经典的动画旋转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文件后,他一直被告知等待...

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

越容易越好。

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

浏览器正在缓存页面。您可以尝试重置值/删除加载图像,当用户使用onunload技巧按下后退按钮时,应该在$(document).ready()触发该图像:单击后退按钮时是否有跨浏览器 onload 事件?

在提示用户下载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。

找到这个:

在浏览器中检测文件下载对话框

这是我基于它的代码:

.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并恢复按钮。