Closed AnikinViktor closed 8 years ago
имеется ListView и ActiveForm
ListView, насколько я понимаю, никак влияет на поведение Pjax?
Ниже привожу diff изменений в yii2-app-basic, которые я внес для воспроизведения проблемы:
SiteController:
diff --git a/controllers/SiteController.php b/controllers/SiteController.php
index 4ffba24..742b92c 100644
--- a/controllers/SiteController.php
+++ b/controllers/SiteController.php
@@ -77,11 +77,17 @@ class SiteController extends Controller
public function actionContact()
{
$model = new ContactForm();
- if ($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) {
- Yii::$app->session->setFlash('contactFormSubmitted');
+ if ($model->load(Yii::$app->request->post())) {
+ if ($model->validate()) {
+ $model->contact(Yii::$app->params['adminEmail']);
+ Yii::$app->session->setFlash('contactFormSubmitted');
+ }
- return $this->refresh();
+ return $this->renderAjax('contact', [
+ 'model' => $model,
+ ]);
}
+
return $this->render('contact', [
'model' => $model,
]);
В модели ContactForm я выключил клиентскую валидацию для полей 'name', 'subject', 'body'
, чтобы только отправка формы и серверная валидация могли показать ошибку
diff --git a/models/ContactForm.php b/models/ContactForm.php
index 361b80b..12267f9 100644
--- a/models/ContactForm.php
+++ b/models/ContactForm.php
@@ -23,11 +23,10 @@ class ContactForm extends Model
{
return [
// name, email, subject and body are required
- [['name', 'email', 'subject', 'body'], 'required'],
+ [['name', 'email', 'subject', 'body'], 'required', 'enableClientValidation' => false],
+ ['email', 'trim'],
// email has to be a valid email address
['email', 'email'],
- // verifyCode needs to be entered correctly
- ['verifyCode', 'captcha'],
];
}
@@ -49,13 +48,7 @@ class ContactForm extends Model
public function contact($email)
{
if ($this->validate()) {
- Yii::$app->mailer->compose()
- ->setTo($email)
- ->setFrom([$this->email => $this->name])
- ->setSubject($this->subject)
- ->setTextBody($this->body)
- ->send();
-
+ Yii::info('The message was sent.');
return true;
}
return false;
В представление добавил Pjax и ListView:
diff --git a/views/site/contact.php b/views/site/contact.php
index b988409..348daa3 100644
--- a/views/site/contact.php
+++ b/views/site/contact.php
@@ -7,6 +7,7 @@
use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use yii\captcha\Captcha;
+use yii\widgets\Pjax;
$this->title = 'Contact';
$this->params['breadcrumbs'][] = $this->title;
@@ -33,6 +34,20 @@ $this->params['breadcrumbs'][] = $this->title;
<?php else: ?>
+ <?php Pjax::begin() ?>
+
+ <p>Sample list view</p>
+
+ <?php echo \yii\widgets\ListView::widget([
+ 'dataProvider' => new \yii\data\ArrayDataProvider([
+ 'allModels' => [
+ ['id' => 1, 'name' => 'SilverFire'],
+ ['id' => 2, 'name' => 'AnikinViktor'],
+ ]
+ ])
+ ]) ?>
+
+
<p>
If you have business inquiries or other questions, please fill out the following form to contact us.
Thank you.
@@ -40,8 +55,10 @@ $this->params['breadcrumbs'][] = $this->title;
<div class="row">
<div class="col-lg-5">
-
- <?php $form = ActiveForm::begin(['id' => 'contact-form']); ?>
+ <?php $form = ActiveForm::begin([
+ 'id' => 'contact-form',
+ 'options' => ['enctype' => 'multipart/form-data', 'data-pjax' => true],
+ ]); ?>
<?= $form->field($model, 'name')->textInput(['autofocus' => true]) ?>
@@ -64,5 +81,6 @@ $this->params['breadcrumbs'][] = $this->title;
</div>
</div>
+ <?php Pjax::end() ?>
<?php endif; ?>
</div>
Заполняю форму, оставляю одно из обязательных полей незаполненным. На клиенте ошибки нет, так как валидацию я отключил. Нажимаю submit, форма получает ответ от сервера и подсвечивает незаполненное поле красным. Поля, для которых клиентская валидация включена нормально реагируют.
Проблему воспроизвести не смог.
Зачем Вы отключаете валидацию на клиенте??? В своем сообщении я указывал о том, что после перезагрузки блока PJAX, в который включена форма, перестают отрабатывать валидаторы на стороне клиента. Включите валидацию на стороне клиента, затем пусть пользователь корректно заполнит модель, отправит ее на сервер, а сервер в свою очередь вернет ее с какой-нибудь ошибкой. Когда форма будет возвращена клиенту - попробуйте оставить пустыми поля, отмеченные как required и увидите, что валидаторы на стороне клиента больше не отрабатывают. Вы можете оставить все поля пустыми - валидатор их не подсветит красным цветом.
Проблема вроде разрешилась обновлением jQuery. Буду тестировать.
Зачем Вы отключаете валидацию на клиенте???
Если у вас включена валидация на клиенте, вы не сможете отправить форму, пока не исправите ошибки. Я мог бы создать отдельное правило валидации в модели, чтобы оно всегда порождало ошибку, но предпочел просто отключить валидацию некоторых правил на клиенте. Все равно я не смог воспроизвести вашу проблему
Проблема вроде разрешилась обновлением jQuery. Буду тестировать.
Если все таки не разрешилась - дайте знать
Добрый день! В блоке Pjax имеется ListView и ActiveForm. Если валидатор на стороне сервера нашел ошибку, то клиенту возвращается форма с ее содержимым и соответствующие сообщения об ошибках. Когда пользователь начинает повторно вводить в данные форму, то оказывается, что валидаторы на стороне клиента не отрабатывают, т.е. вообще не реагируют на ввод данных, хотя соответствующий JS код передан. Я могу ошибаться, но мне кажется проблема в следующем. При первой загрузке страницы к форме прикрепляется атрибут yiiActiveForm - его наличие свидетельствует о том, что форма уже ранее была инициализирована и не требует повторной инициализации.
if ($form.data('yiiActiveForm')) { return; }
Когда форма повторно возвращается через Pjax и помещается в DOM документа, отрабатывает JS код инициализации формы, который пришел вместе с ее HTML кодом. Таким образом повторно отрабатывает init в yii.activeForm.js: запрашивается атрибут yiiActiveForm формы и jQuery успешно возвращает его и насколько я понял, возвращает его из кэша:var cache = this.cache[ this.key( owner ) ]; return key === undefined ? cache : cache[ key ];
Мне удалось обойти эту проблему добавлением<?php $this->registerJs('jQuery("#postDeliveryInfoForm").removeData("yiiActiveForm");'); ?>
в представлении формы сразу после ActiveForm::begin(). Получается после загрузки формы удаляется информация об ее инициализации (если конечно она есть) и форма успешно инициализируется, т.е. начинают работать валидаторы на стороне клиента при изменении содержимого полей.В связи с этим вопрос: может стоит в методе инициализации формы поместить код
if ($form.data('yiiActiveForm')) { $form.removeData('yiiActiveForm'); }
чтобы форма повторно инициализировалась?