1
votes

I have a radio button with two values (required field) based on that value one field is shown (there are two fields which are intially hidden, its shown based on value of radio button) which should be required. So I used conditional validation for the initially hidden fields.

This is my model code:

public function rules()
    {
        return [
            [['receipt_no', 'date_of_payment', 'payment_method_id', 
              'total_amount'], 'required'],   
            ['nonmember_name', 'required', 'whenClient' => function($model) 
             {
                return $model->is_member == 2;
             }, 'enableClientValidation' => false],
             ['member_id', 'required', 'whenClient' => function($model) 
             {
                return $model->is_member == 1;
             }, 'enableClientValidation' => false],
            [['receipt_no', 'date_of_payment', 'payment_method_id', 
              'total_amount','is_member'], 'required','on' => 'receipt'],
        ];
    }

I use a scenario receipt, is_member is the radio button field. If I select a value of 1 for is_member then field member_id is visible and it should be a required one. If is_member has a value 2 then nonmember_name is displayed and it should become a required field. With my code in model I managed to achieve it. But now other actions (saving a new row of data into model) using this model is having error

Array ( [nonmember_name] => Array ( [0] => Name cannot be blank. ) )

So my question is how can I make conditional validation specific to a scenario (I think that my error is due to required rule defined in conditional validation )

EDIT:

This is my radio button

<?= $form->field($model, 'is_member')->radioList(array('1'=>'Member',2=>'Non Member'))->label('Member or Not'); ?>
2

2 Answers

7
votes

In rules

public function rules()
{
    return [
       [
          'nonmember_name', 
          'required', 
          'when' => function ($model) { 
              return $model->is_member == 2; 
          }, 
          'whenClient' => "function (attribute, value) { 
              return $('#id').val() == '2'; 
          }"
       ]
    ];
}
0
votes

I prefer to use functions inside the model's rules, which makes it a lot easier to work with in the future.

One thing to mention that a lot of answers don't mention, is that you MUST manually re-trigger the Yii2 client side validation!

$("#w0").yiiActiveForm("validateAttribute", "createuserform-trainer_id");

In my example below, there are 2 types of accounts: trainer and trainee. In my admin panel, the admin can create a new user. If they choose "trainer" there is nothing more to do. If they choose a "trainee", that "trainee" must be assigned a "trainer" to go under.

So in code terms:

If user role == trainee, trainer_id is required and show it's form input. Else hide the trainer_id input and trainer_id will not be required.


Model rules:

public function rules()
{
    return [
        [
            'trainer_id', 'required', 'when' => function ($model) {
                return $model->role == 2;
            }, 'whenClient' => "isUserTypeTraineeChosen"
        ],
    ];
}

View after your form:

<?php $this->registerJs('
    function isUserTypeTraineeChosen (attribute, value) {

        if ($("#createuserform-role").val() == 2) {
            $(".field-createuserform-trainer_id").show();
        } else {
            $("#createuserform-trainer_id").val(null);
            $(".field-createuserform-trainer_id").hide();
        }

        return ($("#createuserform-role").val() == 2) ? true : false;

    };

    jQuery( "#createuserform-role" ).change(function() {
        $("#w0").yiiActiveForm("validateAttribute", "createuserform-trainer_id");
    });

    jQuery( "#createuserform-role" ).keyup(function() {
        $("#w0").yiiActiveForm("validateAttribute", "createuserform-trainer_id");
    });
'); ?>

Note: This is a dropdown list, so change and keyup both are necessary to accurately detect it's change statuses. If your not using a dropdown, then both may not be necessary.

I also have targeted the trainer_id input to be hidden by default using CSS, as the default user type is a trainer.