Yii2: ActiveForm Ajax validation not working

Created on 12 Dec 2017  ·  14Comments  ·  Source: yiisoft/yii2

What steps will reproduce the problem?

$form = ActiveForm::begin([
    'id' => 'update-form',
    'enableAjaxValidation' => true,
    'validateOnSubmit' => true,
]);
ActiveForm::end();
echo $form->field($model, 'name')->textInput(['form' => 'update-form']);

<button type="submit" form="update-form">Сохранить</button>

What is the expected result?

I want see ajax validation error for attribute "name".

What do you get instead?

I non't see validation error for attribute "name".

Additional info

| Q | A
| ---------------- | ---
| Yii version | 2.0.13
| PHP version | 7.0
| Operating system | CentOS

ready for adoption bug

Most helpful comment

@samdark I do not think this is a mistake. The logic of ActiveForm and widgets just does not allow me to do what I need. This is normal, I think. But I think that the filed method call after the ActiveForm::end () should throw an exception.

All 14 comments

What's the form model you use?

It works with submit button, but validation for attribute 'name' is not working.
My model:

class SameModel extend Model
{
    public $name;

    public function rules()
    {
        return [
            ['name', 'safe'],
            ['name', 'string', 'length' =>  [3, 150]],
        ];
    }
}

I updated the issue.

What value you're trying to submit?

What value you're trying to submit?

Empty value, value of two symbols and more then 150 symbols.

Maybe script framework/assets/yii.activeForm.js does not get attribute "name"?

Any errors in javascript browser console?

Console don't have any errors.
I write test:
Model:

class SameModel extends \yii\base\Model
{
    public $name;
    public $testAttribute;

    public function rules()
    {
        return [
            [['name', 'testAttribute'], 'safe'],
            [['name', 'testAttribute'], 'string', 'length' =>  [3, 150]],
        ];
    }
}

View:

$model = new SameModel();
$form = \yii\widgets\ActiveForm::begin([
    'id' => 'update-form',
    'enableAjaxValidation' => true,
    'validateOnSubmit' => true,
]);
echo $form->field($model, 'testAttribute')->textInput();
ActiveForm::end();
echo $form->field($model, 'name')->textInput(['form' => 'update-form']);
echo '<button type="submit" form="update-form">Save</button>'.PHP_EOL;

I see this source code for this test:

<form id="update-form" action="/index.php?r=advertisment%2Fupdate" method="post">
    <input type="hidden" name="_csrf" value="3XyXYVBwsDCNkkZjCMOvMAChAOPSZIqlElGFLDTd9jX-NQ-AJwypkbuzctXLKVIA6s7i7liBh1NofTHrVUeIhQ==">

    <!-- It works -->
    <div class="form-group field-samemodel-testattribute">
        <label class="control-label" for="samemodel-testattribute">Test Attribute</label>
        <input type="text" id="samemodel-testattribute" class="form-control" name="SameModel[testAttribute]">
        <div class="help-block"></div>
    </div>
</form>

<!-- It not works -->
<div class="form-group field-samemodel-name">
    <label class="control-label" for="samemodel-name">Name</label>
    <input type="text" id="samemodel-name" class="form-control" name="SameModel[name]" form="update-form">
    <div class="help-block"></div>
</div>

<!-- ActiveForm init script -->
jQuery('#update-form').yiiActiveForm([
    {
        "id":"samemodel-testattribute",
        "name":"testAttribute",
        "container":".field-samemodel-testattribute",
        "input":"#samemodel-testattribute",
        "enableAjaxValidation":true,
        "validate":function (attribute, value, messages, deferred, $form) {
    yii.validation.string(value, messages, {"message":"Значение «Test Attribute» должно быть строкой.","min":3,"tooShort":"Значение «Test Attribute» должно содержать минимум 3 символа.","max":150,"tooLong":"Значение «Test Attribute» должно содержать максимум 150 символов.","skipOnEmpty":1});
        }
    }
], []);

ActiveForm init script not't contains "name" attribute.

ActiveForm writes init script after call ActiveForm::end();
If i add ActiveForm field after call ActiveForm::end(), in the init script do not adds new attribute.
How i can add attribute into the ActiveForm js object after call ActiveForm::end()?

Not sure if it'll make a difference but you're closing the ActiveForm widget immediately after creating it.

try.

$form = ActiveForm::begin([
    'id' => 'update-form',
    'enableAjaxValidation' => true,
    'validateOnSubmit' => true,
]);
echo $form->field($model, 'name')->textInput(['form' => 'update-form']);
echo '<button type="submit" form="update-form">Сохранить</button>';
ActiveForm::end();

Not sure if it'll make a difference but you're closing the ActiveForm widget immediately after creating it.

I am use correct html structure. See https://www.w3schools.com/tags/att_input_form.asp
How do you think to solve this situation?

<!-- It is widget -->
<div id = "left-menu">
  <input type="text" name="f1_name" value="f1" />
  <button type="submit" form="f1">Submit f1</button>
  <button type="submit" form="f1">Submit f2</button>
</div>

<!-- It is view -->
<div id="forms-container">
  <form id="f1" method="post">
  <input type="text" name="f1_any" value="f1" />
  </form>

  <form id="f2"  method="post">
  <input type="text" name="f2_name" value="f2" />
  </form>
</div>

The HTML structure is irrelevant here.
If you're ending the ActiveForm widget its already generated the validation JS so any subsequent calls to ->field() will do nothing!

I agree with this statement.
I tried to use a design that works:

ob_start();
echo $form->field($model, 'name')->textInput(['form' => 'update-form']);
$nameField = ob_get_clean();

ActiveForm::end();

echo $nameField;

More elegant solution is not provided?

Why do you need the input field outside the form?

Why do you need the input field outside the form?

This is a very rare case for me. This structure is born from the work of the designer.
Several forms are linked, but displayed in one section. I can not put one form inside another, and this is necessary, because I have fields as the user should see them.

@samdark I do not think this is a mistake. The logic of ActiveForm and widgets just does not allow me to do what I need. This is normal, I think. But I think that the filed method call after the ActiveForm::end () should throw an exception.

Was this page helpful?
0 / 5 - 0 ratings