Не работает JS в Yii2 - как поправить?

Есть код в _form.php вместе с целевой кнопкой 'submitButton' которую необходимо сделать неактивной, пока пусты поля формы. JS пока написан для одного поля 'first_name':

<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;

/* @var $this yii\web\View */
/* @var $model app\models\Contact */
/* @var $form yii\widgets\ActiveForm */

$myJs = <<<JS
   $('#first_name').change(function() {
   $('#my_button').removeAttr('disabled');
   })
JS;

$this->registerJs($myJs);
?>

<div class="contact-form">

    <?php $form = ActiveForm::begin(); ?>

    <?= $form->field($model, 'first_name')->textInput(['maxlength' => true, 'class' => 'form-control inputNotNull'])->label('Имя <span class="note">* поле обязательно к заполнению</span>') ?>

    <?= $form->field($model, 'last_name')->textInput(['maxlength' => true, 'class' => 'form-control inputNotNull'])->label('Фамилия <span class="note">* поле обязательно к заполнению</span>') ?>

    <?= $form->field($model, 'middle_name')->textInput(['maxlength' => true, 'class' => 'form-control inputNotNull'])->label('Отчество') ?>

    <?= $form->field($model, 'internal_phone')->textInput(['maxlength' => true, 'class' => 'form-control inputNotNull'])->label('Вн.телефон <span class="note">* поле обязательно к заполнению</span>') ?>

    <?= $form->field($model, 'mobile_phone')->textInput(['maxlength' => true, 'class' => 'form-control inputNotNull'])->label('Моб.телефон <span class="note">* поле обязательно к заполнению</span>') ?>

    <?= $form->field($model, 'email_address')->textInput(['maxlength' => true, 'class' => 'form-control inputNotNull'])->label('Email адрес <span class="note">* поле обязательно к заполнению</span>') ?>

    <div class="form-group">
        <?= Html::submitButton('Добавить', ['class' => 'btn btn-success', 'name' => 'test-button',
            'id' => 'my_button', 'disabled' => 'disabled', /*'onclick' => '$("#my_button").attr("disabled", "disabled")'*/]) ?>
    </div>

    <?php ActiveForm::end(); ?>

</div>

assets/AppAsset.php:

<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace app\assets;

use yii\web\AssetBundle;

/**
 * Main application asset bundle.
 *
 * @author Qiang Xue <[email protected]>
 * @since 2.0
 */
class AppAsset extends AssetBundle

{
    public $basePath = '@webroot';
    public $baseUrl = '@web';
    public $css = [
        'css/site.css',
    ];
    public $js = [
    ];
    public $depends = [
        'yii\web\YiiAsset',
        'yii\bootstrap4\BootstrapAsset',
    ];
//    public $jsOptions = ['position' => \yii\web\View::POS_HEAD];
} 
  1. Как всегда - кто виноват и что делать (в приложении к коду)?
  2. Почему при варианте написания, указанном ниже, не опознается jQuery:

Ошибка: syntax error, unexpected token "(", expecting variable or "{" or "$"

 $this->registerJs(
$('#first_name').change(function() {
   $('#my_button').removeAttr('disabled');
   })
);

Ответы (3 шт):

Автор решения: Алексей Шиманский

Всё, что написано в registerJs должно быть в виде строки!

https://www.yiiframework.com/doc/api/2.0/yii-web-view#registerJs()-detail

public void registerJs ( $js, $position = self::POS_READY, $key = null )

$js - string - The JS code block to be registered
        ^---------

Потому что туда НЕ принимается какой-то callback.

Как следствие можно написать примерно так:

$js = <<<JS
    $('#first_name').change(function() {
       $('#my_button').removeAttr('disabled');
    });
JS;
$this->registerJs($js);

а вообще, не проще ли испльзовать сразу теги <script> или ассеты?


кто виноват ?

Виноваты вы, потому что не читаете доки! :))


Почему при таком подходе всё равно не работает JS

Потому что на страницы нет элемента с id first_name

Если разработчик не указывает свой id, то ActiveForm генерирует его автоматически по формуле strtolower(имя модели)-strtolower(имя атрибута)

Например имя модели TestLogicAction а имя атрибута func_type, то будет сгенерирован идентификатор testlogicaction-func_type. Имя модели всё слитно.

→ Ссылка
Автор решения: Simply One

в html-коде браузера нашел id элемента, сформированный Yii2 (в моем случае 'contact-first_name' - где 'contact', очевидно, название модели yii-проекта) и вставил его в код JS. все заработало:

$myJs = <<<JS
   $('#contact-first_name').change(function() {
   $('#my_button').removeAttr('disabled');
   })
JS;

за подсказку в выявлении ошибки спасибо @Алексей Шиманский

→ Ссылка
Автор решения: Евгений Малеев

На сколько помню тебе нужно было на несколько полей сделать проверку.

  1. Выбираешь поля устанавливая класс inputNotNull:
<?= $form->field($model, 'first_name')->textInput(['maxlength' => true, 'class' => 'form-control inputNotNull'])->label('Имя <span class="note">* поле обязательно к заполнению</span>') ?>

<?= $form->field($model, 'last_name')->textInput(['maxlength' => true, 'class' => 'form-control inputNotNull'])->label('Фамилия <span class="note">* поле обязательно к заполнению</span>') ?>

  1. регистрируешь скрипт (лучше отдельным файлом, что бы можно было использовать в других местах. Но просто текстом тоже нормально:
function verifyNotNull() //функция проверки на пустоту
{
    if ($(this).val().trim()){
        $("#disabledBtn").prop('disabled', false);
    }else{
        $("#disabledBtn").prop('disabled', true);
    }

}

$(".posts-form").on("change", "input.inputNotNull", function (){ //накидываем обработчик событий на класс inputNotNull
    $('.inputNotNull').each(
        verifyNotNull
        ); // проверяем все инпуты в posts-form с классом inputNotNull на пустоту
});

Проверен. Работает.

→ Ссылка