Creating a custom client-side validation

In the Writing your own validators recipe, we created a standalone validator. In this recipe, we will modify a validator to create extra client-side validation, which also checks the number of words.

Getting ready

Create a new application by using the Composer package manger, as described in the official guide at http://www.yiiframework.com/doc-2.0/guide-startinstallation.html.

How to do it...

  1. Create @app/components/WordsValidator.php as follows:
    <?php
    namespace appcomponents;
    use yiivalidatorsValidator;
    class WordsValidator extends Validator
    {
        public $size = 50;
        public $message = 'The number of words must be less than {size}';
        public function validateValue($value)
        {
            preg_match_all('/(w+)/i', $value, $matches);
            if (count($matches[0]) > $this->size) {
                return [$this->message, ['size' => $this->size]];
            }
        }
        public function clientValidateAttribute($model, $attribute, $view)
        {
            $message = strtr($this->message, ['{size}' => $this->size]);
            return <<<JS
            if (value.split(/w+/gi).length > $this->size ) {
                messages.push("$message");
            }
            JS;
        }
    }
  2. Create @app/models/Article.php as follows:
    <?php
    namespace appmodels;
    use appcomponentsWordsValidator;
    use yiiaseModel;
    class Article extends Model
    {
        public $title;
        public function rules()
        {
            return [
                ['title', 'string'],
                ['title', WordsValidator::className(), 'size' => 10],
            ];
        }
    }
  3. Create @app/controllers/ValidationController.php as follows:
    <?php
    namespace appcontrollers;
    use appmodelsArticle;
    use Yii;
    use yiiwebController;
    class ValidationController extends Controller
    {
        public function actionIndex()
        {
            $model = new Article();
            if ($model->load(Yii::$app->request->post()) && $model->validate()) {
                Yii::$app->session->setFlash('success', 'Model is valid');
            }
            return $this->render('index', [
                'model' => $model,
            ]);
        }
    }
  4. Create @app/views/validation/index.php as follows:
    <?php
    use yiiootstrapActiveForm;
    use yiihelpersHtml;
    ?>
    <h1>Article form</h1>
    <?php if (Yii::$app->session->hasFlash('success')): ?>
        <div class="alert alert-success"><?= Yii::$app->session->getFlash('success'); ?></div>
    <?php endif; ?>
    <?php $form = ActiveForm::begin(); ?>
        <?= $form->field($model, 'title') ?>
        <div class="form-group">
            <?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?>
        </div>
    <?php ActiveForm::end(); ?>

How it works...

Run the validation controller by opening index.php?r=validation. You will see an example of an incorrect value if you enter more than ten words:

How it works...

If you enter fewer than ten words, client-side validation will be successful:

How it works...

First, we created @app/components/WordsValidator.php, which extends the @yiivalidatorsValidator class, and added the newly-created validator class to the title attribute of the Article model:

..
['title', WordsValidator::className(), 'size' => 10],
..

Inside our validator, we've defined two special methods: validateValue() and clientValidateAttribute().

Our validator class implements the validateValue() method to support data validation out of the context of a data model. The second method just returns the JavaScript needed for performing client-side validation.

There's more...

If we would like to hide validator realization, or want to control all validation processes only on the server-side, we can create a Deferred object.

First, modify the WordsValidator validator as follows:

<?php
namespace appcomponents;
use yiivalidatorsValidator;
use yiihelpersUrl;
class WordsValidator extends Validator
{
    public $size = 50;
    public $message = 'The number of words must be less than {size}';
    public function validateValue($value)
    {
        if (str_word_count($value) > $this->size) {
            return ['The number of words must be less than {size}', ['size' => $this->size]];
        }
        return false;
    }
    public function clientValidateAttribute($model, $attribute, $view)
    {
        $url = Url::toRoute(['validation/check-words']);
        return <<<JS
        deferred.push($.get("$url", {words: value}).done(function(data) {
            if (!data.result) {
                messages.push(data.error);
            }
        }));
        JS;
    }
}

In the preceding code, the deferred variable is provided by Yii, which is an array of Deferred objects. The $.get() jQuery method creates a Deferred object, which is pushed to the deferred array.

Second, add this checkWords action to the validation controller:

public function actionCheckWords()
{
    Yii::$app->response->format = yiiwebResponse::FORMAT_JSON;
    $value = Yii::$app->getRequest()->get('words');
    $validator = new WordsValidator([
    'size' => 10,
    ]);
    $result = $validator->validate($value, $error);
    return ['result' => $result,'error' => $error
    ];
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.74.54