Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yii2: ajax form validation on an ajax submitted form

Tags:

ajax

forms

yii2

I'm wondering if any Yii2 experts can help me understand how best to work with ajax forms combined with Yii ajax validation. I think I can explain the issue without taking you through all of my code.

I am working on a Promo Code entry form where the user enters their promo code into the form, the form is submit via ajax. We then perform a database lookup for the promo code details, validate the code and if the code validates, we want to display the registration form that is hidden on the page.

I have a custom validation function for the form field "code", which is the active field in a model scenario named "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.');
        }
    }

    ...
}

Then in the controller, as the Yii2 Guide suggests, I trap this ajax validation with the following code:

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

}

The above code all works fine and if I remove focus from the $form->field($model, 'code') field on my form, Yii's ajax validation kicks in and displays my custom error message based off of my custom validation logic.

My challenge arises when I go to submit the form. The form submission is also handled through ajax, and therefore the controller action always returns the result of the ActiveForm::validate($model); because if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) will get apply to both the ajax form validation AND on the form submit.

With the above approach, I am forced to return only the results of the ajax validation and not any json data that I may need for additional client side validation, such as displaying the registration form after a valid use code is submitted through the ajax form.

I realize that I can set 'enableAjaxValidation' => false on the ActiveForm and then return my own json data inside the if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) condition. If I do this, I am able to show the registration form because I have my own json data to work with.

Is there a way to have ajax validation on a form that is submitted with ajax? How could you trap the ajax validation separately from the ajax form submission to handle the two events in different manners?

Any suggestions or alternate approaches are GREATLY appreciated!

like image 997
CICSolutions Avatar asked Mar 10 '15 01:03

CICSolutions


2 Answers

I have found solution :

Form :

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

Submit Via 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);
?>

Controller :

/*
     * 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,
        ]);
    }
like image 87
Mahesh Kathiriya Avatar answered Sep 21 '22 18:09

Mahesh Kathiriya


You should set up validationUrl with a different URL compared to the URL that you are submitting the form to. In this way you can have the validation function that would validate and return the return ActiveForm::validate($model); and the normal submit form that does something else.

You can read more about validationUrl here:

like image 23
Mihai P. Avatar answered Sep 24 '22 18:09

Mihai P.