yiisoft / validator

Yii validator library
https://www.yiiframework.com/
BSD 3-Clause "New" or "Revised" License
113 stars 40 forks source link

CompareValidator client validation does not work with prefixed attributes #9

Closed SilverFire closed 4 years ago

SilverFire commented 9 years ago

In case of using form fields with prefixed attributes, the ID of input will be model-prefix-attribute (for example bellow user-0-password). During the generation of client validation JS in CompareValidator, the compareAttribute (which have to contain ID of target input) will be set to model-password instead of model-0-password (see CompareValidator.php:219), so the JS will generate false errors during the validation.

view.php:

use yii\widgets\ActiveForm;

$form = ActiveForm::begin();
foreach ($models as $i => $model) {
    print $form->field($model, "[$i]password");
    print $form->field($model, "[$i]confirm_password");
}
$form->end();

model.php:

class User extents Model {
...
    function rules() {
        return [
            [
                    ['password'],
                    'compare',
                    'compareAttribute' => 'confirm_password',
                    'on' => ['create'],
                ],
        ];
    }
...
}

Workaround: set enableClientValidation to false in model and use ajax validation with ActiveForm::validateMultiple

And I don't know, how to pass full attribute with prefix form ActiveForm to CompareValidator

tafid commented 9 years ago

+1

BesedinSasha commented 9 years ago

:+1:

bladeroot commented 9 years ago

:+1:

SilverFire commented 9 years ago

Any ideas, team?

SilverFire commented 8 years ago

Verified :)

SilverFire commented 8 years ago

Duplicated in https://github.com/yiisoft/yii2/issues/10230

MigueSchpeir commented 8 years ago

Thanks @SilverFire for your assistance in #10230. Any idea on how to solve it?

SilverFire commented 8 years ago

Any ideas how to fix it? I thought before, that current client validation design may be enhanced. The main problem is that we are converting attribute names to IDs and get different problems:

I think that the most reliable option is to:

For example:

<form>
   <div class="model-item" data-id="0" data-model="User">
      <input name="User[0][login]" data-attribute="login" />
      <input name="User[0][name]" data-attribute="name" />
   </div>
   <div class="model-item" data-id="1" data-model="User">
      <input name="User[1][login]" data-attribute="login" />
      <input name="User[1][name]" data-attribute="name" />
   </div>
</form>

Then, for example, we can easily add the following rule:

[['name'], 'required', 'whenClient' => "function (value, attribute) {
    return $(attribute).closest('.model-item').find('[data-attribute=login]').val().length > 0;
}"]

Of course, it will be easier to access login attribute of the current model-item with a proper support in yii.activeForm. For example: attribute.model.getInput('name').val().length > 0

It's a draft. Your thoughts? @yiisoft/core-developers

samdark commented 8 years ago

That's good idea. For 2.1 I've planned to make all Yii JS static so no JS is dynamically added to the page and data- attributes are used for everything.

MigueSchpeir commented 8 years ago

@SilverFire, I've tried your solution but I can't get it to work.

My view:

<?php foreach($items as $i=>$item): ?>
    <tr class="model-item" data-id="<?= $i ?>">
        <td><?= $form->field($item,"[$i]quantity_start")->textInput(['data-attribute' => 'quantity_start'])->label(false); ?></td>
        <td><?= $form->field($item,"[$i]quantity_end")->textInput(['data-attribute' => 'quantity_end'])->label(false); ?></td>
    </tr>
<?php endforeach; ?>

My model's validation:

[['quantity_end'], 'compare', 'compareAttribute' => 'quantity_start', 'operator' => '<=', 'type' => 'number',  
'whenClient' => "function (value, attribute) {
    console.log($(attribute).closest('.model-item').find('[data-attribute=quantity_start]').val());                
}"],

I get undefined in my console.

What I'm doing wrong?

samdark commented 4 years ago

Not going to implement client validation itself in this package.