Почему в Yii2 событие submit у формы происходит дважды?

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Почему в Yii2 событие submit у формы происходит дважды?

Сообщение zelenin »

jekahm писал(а):Благодарю ;) Теперь пришло четкое осознание того, что многие вещи не могут быть реализованы и достигнуты только за счет client-side технологий.
server-side может быть?
jekahm
Сообщения: 30
Зарегистрирован: 2016.01.04, 10:22

Re: Почему в Yii2 событие submit у формы происходит дважды?

Сообщение jekahm »

zelenin писал(а):
jekahm писал(а):Благодарю ;) Теперь пришло четкое осознание того, что многие вещи не могут быть реализованы и достигнуты только за счет client-side технологий.
server-side может быть?
Написал, что "НЕ могут быть достигнуты" :)
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Почему в Yii2 событие submit у формы происходит дважды?

Сообщение zelenin »

jekahm писал(а):
zelenin писал(а):
jekahm писал(а):Благодарю ;) Теперь пришло четкое осознание того, что многие вещи не могут быть реализованы и достигнуты только за счет client-side технологий.
server-side может быть?
Написал, что "НЕ могут быть достигнуты" :)
а, ок.
Аватара пользователя
Haku
Сообщения: 58
Зарегистрирован: 2015.03.11, 07:39

Re: Почему в Yii2 событие submit у формы происходит дважды?

Сообщение Haku »

Сейчас делаю отправку данных из "Active Form" с помощью Ajax-запроса и столкнулся с такой же проблемой, но не понял как её решить.

Есть совершенно стандартная форма:

Код: Выделить всё

<?php $form = ActiveForm::begin(['id' => 'user-form']); ?>
	<?= $form->field($model, 'name') ?>
	//...
	<div class="form-group">
		<?= Html::submitButton('Сохранить', ['class' => 'button', 'name' => 'update-button']) ?>
	</div>
<?php ActiveForm::end(); ?>
На которую я повесил обработчик:

Код: Выделить всё

var form = $('#user-form');
form.on('submit', function(event) {
	event.preventDefault();
	var url = '/main/controller/action';
	var data = form.serialize();
	
	$.ajax({
		//...
	});
});
При первом нажатии на "Submit" происходит два одинаковых post-запроса, за исключением того, что во втором запросе к передаваемым данным добавляется "update-button". При последующих нажатиях отправляется один запрос.

Посмотрев в отладчике работу внутреннего скрипта "yii.activeForm.js", понял почему так происходит:
1. В "submitForm: function() {}" не срабатывает условие "if (data.validated) {}".
2. Отправляется первый запрос.
3. Условие "if (data.validated) {}" срабатывает, в форму добавляется <input type="hidden" name="update-button">.
4. Отправляется второй запрос.

Проблема в том, что в первый раз в БД создастся две одинаковых записи, но этого делать не нужно. Я понимаю, что это связано с валидацией данных, но, то ли я не до конца понимаю работу Active Form, то ли у меня неправильно работает js-скрипт. Подскажите, пожалуйста, как сделать правильно, чтобы добавление/редактирование происходило один раз.
tweet9ra
Сообщения: 1
Зарегистрирован: 2019.01.13, 15:55

Re: Почему в Yii2 событие submit у формы происходит дважды?

Сообщение tweet9ra »

Haku писал(а): 2018.08.31, 15:47 Сейчас делаю отправку данных из "Active Form" с помощью Ajax-запроса и столкнулся с такой же проблемой, но не понял как её решить.

Есть совершенно стандартная форма:

Код: Выделить всё

<?php $form = ActiveForm::begin(['id' => 'user-form']); ?>
	<?= $form->field($model, 'name') ?>
	//...
	<div class="form-group">
		<?= Html::submitButton('Сохранить', ['class' => 'button', 'name' => 'update-button']) ?>
	</div>
<?php ActiveForm::end(); ?>
На которую я повесил обработчик:

Код: Выделить всё

var form = $('#user-form');
form.on('submit', function(event) {
	event.preventDefault();
	var url = '/main/controller/action';
	var data = form.serialize();
	
	$.ajax({
		//...
	});
});
При первом нажатии на "Submit" происходит два одинаковых post-запроса, за исключением того, что во втором запросе к передаваемым данным добавляется "update-button". При последующих нажатиях отправляется один запрос.

Посмотрев в отладчике работу внутреннего скрипта "yii.activeForm.js", понял почему так происходит:
1. В "submitForm: function() {}" не срабатывает условие "if (data.validated) {}".
2. Отправляется первый запрос.
3. Условие "if (data.validated) {}" срабатывает, в форму добавляется <input type="hidden" name="update-button">.
4. Отправляется второй запрос.

Проблема в том, что в первый раз в БД создастся две одинаковых записи, но этого делать не нужно. Я понимаю, что это связано с валидацией данных, но, то ли я не до конца понимаю работу Active Form, то ли у меня неправильно работает js-скрипт. Подскажите, пожалуйста, как сделать правильно, чтобы добавление/редактирование происходило один раз.
Мне помог данный способ:
вместо

Код: Выделить всё

 form.on('submit', function(e){}) 
использовать

Код: Выделить всё

 
 form.on('beforeValidate', function(){
 	return false; // Если вернуть false, то форма не будет отправлена
 }) 
 
ziggrun
Сообщения: 14
Зарегистрирован: 2015.09.17, 00:15

Re: Почему в Yii2 событие submit у формы происходит дважды?

Сообщение ziggrun »

Столкнулся с такой же проблемой и нашел ее решение. Как верно подметил товарищ выше, при включенной ajax валидации в ActiveForm отправляется насколько запросов (валидация/отправка формы). Валидацию нужно вынести в отдельный экшен. Вот пример кода:

Код: Выделить всё

<?php $form = \yii\widgets\ActiveForm::begin([
    'id' => 'my-form-id',
    'action' => 'save-url',
    'enableAjaxValidation' => true,
    'validationUrl' => 'validate',
]); ?>

public function actionValidate()
{
    $model = new MyModel();
    $request = \Yii::$app->getRequest();
    if ($request->isPost && $model->load($request->post())) {
        \Yii::$app->response->format = Response::FORMAT_JSON;
        return ActiveForm::validate($model);
    }
}
mikola123
Сообщения: 42
Зарегистрирован: 2016.04.22, 22:39

Re: Почему в Yii2 событие submit у формы происходит дважды?

Сообщение mikola123 »

jekahm писал(а): 2016.09.05, 14:27
rugabarbo писал(а):
jekahm писал(а): Потому как логично, что в ином случае форма будет отправлена несколько раз, если кнопка не будет заблокирована мгновенно.
В идеале после прохождения валидации должно быть, как здесь https://jsfiddle.net/m146a9b2/
В идеале да, но включите JS-профайлер и посмотрите, сколько там всего происходит и может происходить до вызова beforeSubmit. Не удивительно, что при зажатом Enter успевает проскочить 2-3 клика - это всё-таки асинхронная среда.

Вот здесь идёт обсуждение защиты от double-сабмитов на серверной стороне: https://github.com/yiisoft/yii2/issues/10498

Если вам нужно 100% защититься от двойных кликов, то это не решить с помощью JavaScript. Я тоже делаю для всех важных кнопок:

Код: Выделить всё

$('.btn').prop('disabled', true); 
- и в 99.9% случаев это позволяет защититься. Но практика показывает, что в 0.1% случаев всё-таки находятся кретины, успевающие нажать сабмит очень-очень быстро два раза подряд :mrgreen:

Хотите гарантий - это не про JavaScript.
JavaScript - про удобство клиента.
Благодарю вас, а так же участников данной темы ;) Теперь пришло четкое осознание того, что многие вещи не могут быть реализованы и достигнуты только за счет client-side технологий. И спасибо за ссылку о server-side решении.
Проверил такая проблема действительно есть. Кликать дважды не обязательно, форма отправляется клавишей Enter.
1. Зажать Enter
2. Сработал beforeSubmit, Submit = false, return false
3. Ждем выполнения Ajax, Submit = true
4. И вот тут начинается вакханалия, форма отправляется столько раз сколько успеет за 200мс, а это от 4 до 6 раз. Клавиша Enter все еще зажата.
Не очень понимаю почему все положили хер, мол юзер так никогда не сделает.

Долго по коду не лазил, но нашел вот такой вызов. Отсюда идет данная ошибка:

yii.activeForm.js

Код: Выделить всё

if (data.submitting) {
                        // delay callback so that the form can be submitted without problem
                        window.setTimeout(function () {
                            updateInputs($form, messages, submitting);
                        }, 200);
                    } else {
Выложу на Github. У себя поставил вместо 200 -> 0. Форма отправляется нормально.
Ответить