如何在不触发变更事件的情况下替换表格?

时间:2019-10-20 12:22:05

标签: javascript jquery

我想用向服务器的AJAX请求验证form,然后将Web浏览器中的form html与服务器中的form html交换,因为理论上很容易实现。事实证明,这是一场噩梦,因为change事件被触发,而用户在第一次触发第一个更改事件的第一次交互之后没有进一步交互。因此,正在发生向服务器的AJAX请求的无限循环。

html form位于div内,该类具有“容器mb-4”类。这是JS代码-

        var _cont = $('.container.mb-4')
        var _form = $('.custom-form')

        function ajax_validation(form) {

            form.on('change', 'input, select, textarea', function() {

                form_data = form.serialize()

                    $.ajax({
                        url: "/form/6/",
                        type: "POST",
                        data: form_data,
                        success: function(data) {
                            if(!(data['success'])) {
                                _cont.empty()
                                _cont.append(data['form_html'])
                                form = _cont.find('form')
                                ajax_validation(form)
                            }
                        },
                        error: function () {
                            form.find('.error-message').show()
                        }
                    });


            })
        }

        ajax_validation(_form)

我假设发生的更改事件是由于服务器返回的form input字段具有不同的csrf令牌作为前一个input字段的值而触发的-其他所有字段都是相同。因此,一个显而易见的解决方案是保留相同的csrf令牌。但是我想了解为什么JS代码不起作用。我认为销毁form会销毁与其绑定的change事件。因此不知所措来解释这个无限循环。我该如何更改它,以便我可以只交换表单而不会触发另一个更改事件,直到用户确实进行了更改为止。

3 个答案:

答案 0 :(得分:0)

  • events中使用function并不是一件好事
  • 此外,您在input , select , textarea处进行序列化的事件还需要选择closest()表单

尝试下一个代码

var _cont = $('.container.mb-4');
var _form = $('.custom-form');

_cont.on('change', 'form input,form select,form textarea', function() {
      var ThisForm = $(this).closest('form');
      var form_data = ThisForm.serialize();
      $.ajax({
        url: "/form/6/",
        type: "POST",
        data: form_data,
        success: function(data) {
           if(!(data['success'])) {
              _cont.html(data['form_html']);
           }
        },
        error: function () {
           ThisForm.find('.error-message').show()
        }
    });
});
  • 逻辑上if(!(data['success'])) {应该是if(data['success']) {

答案 1 :(得分:0)

首先让我们了解您遇到的问题。您有一个名为function的{​​{1}},它在表单元素上定义了一个更改事件,在响应时将调用ajax_validation。因此,如果您的元素发生任何更改,则新请求将发送到服务器。因此,如果更改了任何值(例如令牌),则将再次发送请求。您可以使用信号量,如下所示:

ajax_validation

类似的事情暂时可以解决您的问题,但是您应该考虑重构代码,因为您所经历的是众所周知的,称为callback hell

答案 2 :(得分:0)

结果是,服务器的密码字段变为空白-如果使用PasswordInput小部件,则此django必须开箱即用。因此,该表单将替换为缺少以前密码输入的新表单。然后,浏览器将自动填充密码值应用于触发更改事件的表单。

这是我的代码。它会检查要发送的用于验证的form_data确实与减去csrf令牌之前的形式确实有所不同。

它基于穆罕默德的答案-

        var _cont = $('.container.mb-4');
        var _form = $('.custom-form');

        var prev_data = undefined

        _cont.on('change', 'form input,form select,form textarea', function() {
            var ThisForm = $(this).closest('form');

            var form_data_wo_csrf = ThisForm.find("input, textarea, select").not("input[type='hidden']").serialize()

            if(form_data_wo_csrf == prev_data) {
                return
            }

            var form_data = ThisForm.serialize()

            $.ajax({
                url: "/form/6/",
                type: "POST",
                data: form_data,
                success: function(data) {
                if(!(data['success'])) {
                    _cont.html(data['form_html']);
                    prev_data = form_data_wo_csrf
                }
                },
                error: function () {
                ThisForm.find('.error-message').show()
                }
            });
        });