using 'whenClient' for complex client side validation

You have a 'Category' model with Id, Name and Visibility (boolean, where 0 = Public, and 1 = Private).

And you have a 'Books' model with Id, Name, Category_Id and Description.

When you create a 'Book' you must choose a 'Category', and follow this rule:

if (Category->Visibility == 0) { Books.Description is required }

To do this validation client side we can use whenClient.

In your Books model, use this rule:

public function rules()
    return [
	['description', 'required',
       'whenClient' => 'bookVisibility',
	   'when' => function($model) {
			return $model->category->visibility == 0;

We have the server validation, and must create the javascript function 'bookVisibility' for the client side.

We'll need category->visibility information on the browser. You can use ajax calls for that. But if it's not too many records, you can use a js object and save same requests. For this object, we can use a getter in Books model:

public static function getCategoryVisibility()
    $data = Category::find()->asArray()->all();
    $data = ArrayHelper::map($data, 'id', 'visibility');
    $data = Json::encode($data);
    return $data;

We need a hidden field for the visibility information in books/_form.php:

<?= Html::hiddenInput('visibility', 0, ['id' => 'visibilityHidden']) ?>

Is the same file, we can put the js function:

$getVisibility = $model->getCategoryVisibility();
	var jsBookVisibility = $getVisibility;
	$('#categoryDropDown').change(function() {

	function bookVisibility (attribute, value) {
        return $('#visibilityHidden').val() == '0';

You must have a dropdown with ['id'=>'name'] for categories in your _form.

That's all. With this code you can't submit a form that not follow the rule.