Как заменить форму, не вызывая событие изменения? - PullRequest
0 голосов
/ 20 октября 2019

Я хотел бы проверить form с помощью AJAX-запроса к серверу, а затем заменить 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 голосов
/ 20 октября 2019

Сначала давайте разберемся с проблемой, которая у вас есть. У вас есть function с именем ajax_validation, который определяет событие изменения в элементах формы, которое в ответ вызовет ajax_validation. Таким образом, если какие-либо изменения происходят с вашими элементами, то на сервер отправляется новый запрос. Таким образом, если какое-либо значение будет изменено, например, токен, запрос будет отправлен снова. Вы можете использовать семафор, например:

    var semaphore = true;
    function ajax_validation(form) {

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

            if (!semaphore) return;
            semaphore = false;
            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)
                        }
                        semaphore = true;
                    },
                    error: function () {
                        form.find('.error-message').show()
                    }
                });


        })
    }

Что-то вроде этого должно решить вашу проблему в настоящее время, но вы должны рассмотреть возможность рефакторинга вашего кода, потому что то, что вы испытываете, хорошо известно и называется обратный вызов ада .

0 голосов
/ 20 октября 2019

Оказывается, поле пароля возвращалось пустым с сервера - это django должно делать из коробки, если используется виджет PasswordInput. Таким образом, форма заменяется новой формой, в которой отсутствует пароль, введенный ранее. Затем браузер применял значение пароля автозаполнения к форме, которая вызывала событие изменения.

Теперь это мой код. Он проверяет, что 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()
                }
            });
        });
0 голосов
/ 20 октября 2019
  • Нехорошо использовать 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']) {
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...