Yii2: проверка формы ajax на представленной форме ajax

Мне интересно, могут ли какие-либо эксперты Yii2 помочь мне понять, как лучше всего работать с формами ajax в сочетании с валидацией Yii ajax. Думаю, я могу объяснить проблему, не пропустив весь мой код.

Я работаю над формой ввода промо-кода, в которой пользователь вводит свой промо-код в форму, форма отправляется через ajax. Затем мы выполняем поиск базы данных для деталей промо-кода, проверяем код и, если код проверяется, мы хотим отобразить регистрационную форму, которая скрыта на странице.

У меня есть специальная функция проверки для поля формы "code", которая является активным полем в модельном сценарии с именем "register".

class UserCode extends ActiveRecord
{
    ... 

    public function scenarios()
    {
        return [
            'register' => ['code'],
        ];
    }

    public function rules()
    {
        return [
            [['code'], 'required'],
            [['code'], 'validateUserCode', 'on' => ['register']],
        ];
    }

    public function validateUserCode($attribute, $params)
    {
        // perform all my custom logic to determine if the code is valid

        if ($code_invalid) {
            $this->addError($attribute, 'Sorry, this code is invalid.');
        }
    }

    ...
}

Затем в контроллере, как предлагает Yii2 Guide, я задерживаю эту проверку ajax следующим кодом:

public function actionValidate() {

    $model = new UserCode(['scenario' => 'register']);

    if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
        Yii::$app->response->format = Response::FORMAT_JSON;
        return ActiveForm::validate($model);
    }

    // no logic can be run after the above code b/c the form is submit with ajax 
    // and therefore always trapped in the Yii::$app->request->isAjax conditional

}

Приведенный выше код работает отлично, и если я удаляю фокус из поля $form->field($model, 'code') в моей форме, выполняется проверка Yii ajax и выводит мое пользовательское сообщение об ошибке на основе моей пользовательской логики проверки.

Моя задача возникает, когда я отправляю форму. Подача формы также обрабатывается через ajax, и поэтому действие контроллера всегда возвращает результат ActiveForm::validate($model);, потому что if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) будет применяться как к валидации формы ajax, так и к форме submit.

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

Я понимаю, что я могу установить 'enableAjaxValidation' => false в ActiveForm, а затем вернуть свои собственные данные json внутри условия if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())). Если я это сделаю, я могу показать регистрационную форму, потому что у меня есть свои собственные данные json для работы.

Есть ли способ иметь ajax-проверку в форме, представленной с помощью ajax? Как вы могли бы отследить проверку ajax отдельно от представления формы ajax для обработки двух событий разными способами?

Любые предложения или альтернативные подходы высоко ценятся!

Ответ 1

Вы должны настроить validationUrl с другим URL-адресом по сравнению с URL-адресом, которому вы отправляете форму. Таким образом, вы можете иметь функцию проверки, которая будет проверять и возвращать return ActiveForm::validate($model); и нормальную форму отправки, которая делает что-то еще.

Подробнее о validationUrl здесь:

Ответ 2

Я нашел решение:

Форма:

 <?php
    $form = ActiveForm::begin(['id' => 'form-add-contact', 'enableAjaxValidation' => true, 'validationUrl' => Yii::$app->urlManager->createUrl('contacts/contacts/contact-validate')]);
    ?>

Отправить через Ajax:

<?php
$script = <<< JS

   $(document).ready(function () { 
        $("#form-add-contact").on('beforeSubmit', function (event) { 
            event.preventDefault();            
            var form_data = new FormData($('#form-add-contact')[0]);
            $.ajax({
                   url: $("#form-add-contact").attr('action'), 
                   dataType: 'JSON',  
                   cache: false,
                   contentType: false,
                   processData: false,
                   data: form_data, //$(this).serialize(),                      
                   type: 'post',                        
                   beforeSend: function() {
                   },
                   success: function(response){                         
                       toastr.success("",response.message);                            
                   },
                   complete: function() {
                   },
                   error: function (data) {
                      toastr.warning("","There may a error on uploading. Try again later");    
                   }
                });                
            return false;
        });
    });       

JS;
$this->registerJs($script);
?>

Контроллер:

/*
     * CREATE CONTACT FORM  AJAX VALIDATION ACTION
     */

    public function actionContactValidate() {
        $model = new ContactsManagement();
        if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
            $model->company_id = Yii::$app->user->identity->company_id;
            $model->created_at = time();
            \Yii::$app->response->format = Response::FORMAT_JSON;
            return ActiveForm::validate($model);
        }
    }


/**
     * Quick Add Contact Action
     * @param type $id
     * @return type
     */
    public function actionAddContact() {           

        $model = new ContactsManagement();

        if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {

            $transaction = \Yii::$app->db->beginTransaction();

            try {
                if ($model->validate()) {
                    $flag = $model->save(false);
                    if ($flag == true) {
                        $transaction->commit();

                        return Json::encode(array( 'status' => 'success', 'type' => 'success', 'message' => 'Contact created successfully.'));
                    } else {
                        $transaction->rollBack();
                    }
                } else {
                    return Json::encode(array('status' => 'warning', 'type' => 'warning', 'message' => 'Contact can not created.'));
                }
            } catch (Exception $ex) {
                $transaction->rollBack();
            }
        }

        return $this->renderAjax('_add_form', [
                    'model' => $model,
        ]);
    }