Программирование, веб-кодинг

Pjax на ActiveForm и на GridView на странице и в модальном окне ("Пиджак в окне")

Pjax на ActiveForm и на GridView на странице и в модальном окне ("Пиджак в окне")

Рассмотрим 2 случая: когда форма находится на странице сайта и её нужно отправить асинхронно по Pjax; и второй случай - когда форму нужно вывести в модальном окне и тоже отправить асинхронно.

1. Случай формы ActiveForm по Pjax на странице

Пригодится для лендингов. Форму одеваем в пиджак (Pjax::begin() и Pjax::end()), чтобы обновлялась она асинхронно при ответе с сервера (мне нужно вывести вместо формы на её месте сообщение о результате отправки сообщения администратору сайта). И, второе, не забываем у ActiveForm в опциях добавить 'data-pjax' => true, чтобы форма отправляла данные асинхронно.

<?php yii\widgets\Pjax::begin() ?>
    <?php if (!empty($success)): ?>
        <div class="alert alert-success lead">
            Спасибо! Ваша заявка отправлена. Мы скоро с вами свяжемся.
    </div>
    <?php else: ?>
        <?php $form = ActiveForm::begin(['options' => ['id' => 'contactForm1', 'data-pjax' => true, 'class'=>'form form-register1 text-left'], 'fieldConfig' => ['template' => "{beginWrapper}\n{hint}\n{error}\n{input}\n{endWrapper}"]]); ?>
            ...
        <?php ActiveForm::end(); ?>
    <?php endif; ?>
<?php Yii\widgets\Pjax::end(); ?>

Дальше в контроллере в действии для этого представления добавляем отдельно проверку для случая isPjax. В модели формы BuycourseForm действие contact(), отправляющее сообщение на email.

public function actionIndex()
{
...
$model = new BuycourseForm();
if(Yii::$app->request->isPjax && $model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) {
$success = true;
return $this->render('landing', [
'success'=>$success,
'model' => $model
]);
}

...
return $this->render('landing', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'model' => $model
]);
}


2. Случай ActiveForm по Pjax в модальном окне ("Пиджак в окне")

Пишу CRM-ку для студии танцев и возникло желание задействовать мощь Pjax. Тем более, что его поддержка встроена в Yii2.

В модальном окне внесения оплаты сохранение оплаты делается через Pjax ("Пиджак в окне"), потому что в модальном окне под формой внесения оплаты находится грид с данными об оплатах этого ученика и таким образом (по pjax) он обновляется на лету и админ видит, что платеж зафиксирован на сервере. При закрытии же самого модального окна, нужно снова обновить ячейку с оплатой в главном гриде "Ученики".

Итак, когда вызывается модальное окно, там форма добавления платежа и грид уже имеющихся платежей. Контроллер PaymentController

public function actionCreate($date=null, $pupil_id=null)
    {
        $model = new Payment();
        $model->date = $date;
        $model->pupil_id = $pupil_id;
        $model->payment_type = 1;
        
        $searchModel = new PaymentSearch();
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams, $pupil_id = $pupil_id);
        
        if (Yii::$app->request->isAjax) {
            
            if ($model->load(Yii::$app->request->post()) && $model->save()) {
                $model = new Payment();
                $model->date = $date;
                $model->pupil_id = $pupil_id;
                $model->payment_type = 1;
            }
            
            return $this->renderAjax('create_ajax', [
                'model' => $model,
                'searchModel' => $searchModel,
                'dataProvider' => $dataProvider,
                'group_id'=> 2,
            ]);
            
        } else {

            if ($model->load(Yii::$app->request->post()) && $model->save()) {
                return $this->redirect(Yii::$app->request->referrer);
            } else {
                return $this->render('create', [
                    'model' => $model,
                    'searchModel' => $searchModel,
                    'dataProvider' => $dataProvider,
                ]);
            }
        }
    }

В виде, что в модальном окне показывается

<?php

use yii\helpers\Html;
use yii\grid\GridView;
use app\components\NumberColumn;
use yii\widgets\Pjax;


/* @var $this yii\web\View */
/* @var $model app\models\Payment */

$this->title = 'Добавить платёж';
$this->params['breadcrumbs'][] = ['label' => 'Payments', 'url' => ['index']];
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="payment-create">

    <?= $this->render('_form_ajax', [
        'model' => $model,
        'group_id' => $group_id,
    ]) ?>

</div>
<hr>


<h3>Последние платежи (<?= $model->pupil->name ?>):</h3>
<?php Pjax::begin(['id' => 'payments']) ?>
    <?= GridView::widget([
            'dataProvider' => $dataProvider,
            //'filterModel' => $searchModel,
            'layout'=>"{items}",
            'showFooter' => true,
            'tableOptions' => [
            'class' => 'table table-striped table-condensed small'
            ],
            'columns' => [
                ['class' => 'yii\grid\SerialColumn'],
                [
                    'attribute' => 'date',
                    'format' =>  ['date', 'dd.MM.YYYY'],
                ],
                [
                    'attribute'=>'payment_type',
                    'label'=>'Тип платежа',
                    //'filter'=>app\models\PaymentType::find()->select(['id', 'title'])->indexBy('id')->column(),
                    //'format'=>'text',//'raw',
                    'value'=>'paymentType.title',
                    /*'content'=>function(app\models\User $model){
                        return $model->profile->getGroupName();
                    },*/
                    /*'value' => function($model){
                        return (isset($model->profile->group_id))
                            ? Html::encode($model->profile->group_id)    
                            : '<span class="not-set">' . Yii::t('user', '(not set)') . '</span>';
                    },*/
                    'footer'=>'Всего: ',
                ],
                [
                    'class' => NumberColumn::className(),
                    'attribute' => 'price',
                ],

                [
                    'class' => 'yii\grid\ActionColumn',
                    'contentOptions' => ['style' => 'white-space: nowrap; text-align: center; letter-spacing: 0.1em; max-width: 7em;'],
                ],
            ],
    ]); ?>
<?php Pjax::end() ?>

Часть _form_ajax для этого вида

<?php

use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use yii\helpers\ArrayHelper;

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

<?php // обновляем грид под формой с оплатой внутри модального окна
    $this->registerJs(
        '$("document").ready(function(){
            $("#new_payment").on("pjax:end", function() {
            $.pjax.reload({container:"#payments"});  //Reload GridView
        });
    });'
    );
?>

<div class="payment-form">
<?php yii\widgets\Pjax::begin(['id' => 'new_payment']) ?>
    <?php $form = ActiveForm::begin(['options' => ['data-pjax' => true], 'layout' => 'horizontal']); ?>
    
    <div class="row clearfix">
        <div class="col-md-12">
            <?= $form->field($model, 'pupil_id')->hiddenInput(['value'=> $model->pupil->user_id])->label(false); ?>
            <div class="form-group field-payment-date required">
                <label class="control-label col-sm-3" for="payment-pupil_id">От</label>
                <div class="col-sm-6">
                    <div class="input-group">
                      <?= $model->pupil->name ?>
                    </div>
                </div>
            </div>
            
            <?= $form->field($model, 'date')->widget(\yii\jui\DatePicker::classname(), [
                'dateFormat' => 'dd.MM.yyyy',
                'language' => 'ru',
                'options'=>['class'=>'form-control'],
            ]) ?>        
        
        
            <?= $form->field($model, 'payment_type')->dropDownList(ArrayHelper::map(app\models\PaymentType::find()->select(['id', 'title'])->all(), 'id', 'title'), ['prompt'=>'- Выберите тип платежа -']) ?>
        
        
            <?= $form->field($model, 'price', ['template' => '
               {label}
               <div class="col-sm-6">
                   <div class="input-group">
                      {input}
                      <div class="input-group-addon">
                         <span class="glyphicon glyphicon-rub"></span>
                      </div>
                   </div>
                   {error}{hint}
               </div>'])->textInput() ?>

            
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-offset-3 col-sm-8">
            <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
        </div>
    </div>
    
    <?php ActiveForm::end(); ?>
<?php yii\widgets\Pjax::end(); ?>
</div>


Важные моменты

  1. В действии actionIndex добавили сохранение данных новой Заметки, если они пришли в запросе post
  2. Обернули виджеты GridView и ActionForm в пиджак
  3. Добавили небольшой скрипт, обновляющий GridView после добавления новой записи

По мотивам – https://nix-tips.ru/yii2-primeryaem-pjax-na-activeform-i-gridview.html