-->

Yii2 custom validator not working as guide suggest

2019-05-11 00:39发布

问题:

I've searched around here for some time today, but I'm unable to understand why my validators aren't working in my model.

I have a Module with a model "Page" in my code below.

I have 2 attributes that I need to use to validate the model. They are hero_link and hero_linked. If hero_linked is true, I want to require hero_link.

In the guide here, they explain the proper syntax for this kind of validator

I have used this syntax in my model, but it doesn't validate as I'd expect. I've added the whenClient property as well, so I can use client side validation here.

my relevant code is below:

// Page model
namespace common\modules\page\models;

use Yii;

class Page extends \yii\db\ActiveRecord
{
    public function rules()
    {
        return [
            [['hero_linked',], 'boolean'],
            [['hero_linked',], 'required'],
            [['hero_link',], 'string', 'max' => 255],
            [
                'hero_link', 
                'required', 
                'when' => function($model) {
                    return $model->hero_linked == true;
                },
                'whenClient' => "function (attribute, value) {
                    return $('#page-hero_linked').val() == '1';
                }",
            ],
        ];
    }
}

// _form view 
<?php $form = ActiveForm::begin(); ?>
    <?= $form->field($model, 'hero_linked')->checkbox() ?>
    <?= $form->field($model, 'hero_link')->textInput(['maxlength' => 255]) ?>
<?php ActiveForm::end(); ?>

The required validator is correctly applied, but it seems to be ignoring the when property, and requiring even though my checkbox is unchecked. Is my syntax incorrect, or am I missing a requirement? Any help is appreciated, Thanks in advance!

回答1:

I guess this is what you want. First use the property "checked" in the whenClient of the input field to get if the checkbox is checked or not.

The hidden field of the checkbox is not an issue.

The whenClient in hero_linked (checkbox) is used to validate the hero_link (textinput) field on change of the checkbox. So you instantly see if the hero_link (textinput) is required or not.

You don't need any additional js code in your form if you use this rules.

But as you might also see that due to the complete name "page-something" this is really fixed to only the "page" model and i guess also depending on the form name. So you should use some other fixed "id's" for both fields in the form.php so this also would also work if you extend your page model to another class.

[
    'hero_linked', 'required',
    'whenClient' => "function (attribute, value) {
        $('form').yiiActiveForm('validateAttribute', 'page-hero_link');
        return true;
    }",
],
[['hero_link',], 'string', 'max' => 255],
[
    'hero_link', 'required', 'when' => function ($model) {
        return $model->hero_linked == true;
    },
    'whenClient' => "function (attribute, value) {
        return $('#page-hero_linked').prop('checked');
    }",
],


回答2:

I found out how to make this work. If you use a checkbox, you cannot use only server or client side validation. I had to use both when and whenClient. I had to register a script in my view so the checked attribute would update on the checkbox.

$('label > #page-hero_linked').click(function(event) {
    var checked = $(this).attr('checked');
    if (checked) {
        $(this).removeAttr('checked');
    }else{
        $(this).attr('checked', '');
    };
});

and below is my validation rule.

[['hero_link'],
'required',
'when' => function($model) {
    return $model->hero_linked == true;
},
'whenClient' => "function (attribute, value) {
    return $('#page-hero_linked').attr('checked');
}",],

All in all, pretty simple code to make it work, but not obvious to me that this much is required from the docs.