problem with pjax form (loaded dynamically) and gridview

Problem: I want to update GridView after submit form (modal window) in pjax style but it redirect to the form generation page.

What I want to do is similar to the wiki Yii 2.0: Pjax on ActiveForm and GridView - Yii2 , but the form is not put into yii\bootstrap\Modal initially but is loaded into #modal when click "Create" button on the page.

I want to display modal form for creating new record (or updating record displayed on GridView), then refresh the GridView after submitting the form. So the form is loaded dynamically.

Here is the code. What it intends to do is:

  • Having an index page with GridView to display data list. It has yii\bootstrap\Modal without any content inside it.

  • When click on "Create" button link on index page, it calls country/create to get the HTML code of the form and insert it into the modal, then it shows the modal window.

  • When click on the "Create" button on the form, it submit the form to country/create. This will return the HTML code of the index page, and I want it to update the GridView part, but it does not. Instead, it redirect to country/create.

Controller CountryController.php


class CountryController extends Controller

[code]{


    public function actionIndex()

    {

        return $this->renderIndex();

    }


    public function actionCreate()

    {

        $model = new Country();


        if ($model->load(Yii::$app->request->post()) && $model->save()) {

            return $this->renderIndex();

        } else {

            return $this->renderAjax('_form', [

                'model' => $model,

            ]);

        }

    }


    private function renderIndex()

    {

        $searchModel = new CountrySearch();

        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);


        return $this->render('index', [

            'searchModel' => $searchModel,

            'dataProvider' => $dataProvider,

        ]);

    }

}

View index.php


<?php


use yii\helpers\Html;

use yii\grid\GridView;

use yii\widgets\Pjax;

use yii\web\View;


/* @var $this yii\web\View */

/* @var $searchModel app\models\CountrySearch */

/* @var $dataProvider yii\data\ActiveDataProvider */


$this->title = Yii::t('app', 'Countries');

$this->params['breadcrumbs'][] = $this->title;


yii\bootstrap\Modal::begin(['id' => 'modal']);

yii\bootstrap\Modal::end();

?>

<div class="country-index">


    <h1><?= Html::encode($this->title) ?></h1>

    <div>Current Time: <?= date('Y/m/d H:i:s') ?></div>


    <p><?= Html::a(Yii::t('app', 'Create Country'),

        ['create'],

        ['class' => 'btn btn-success show-modal']) ?>

    </p>

    <?php Pjax::begin(['id' => 'pjax-grid']); ?>

        <?= GridView::widget([

            'dataProvider' => $dataProvider,

            'filterModel' => $searchModel,

            'columns' => [

                ['class' => 'yii\grid\SerialColumn'],

                'id',

                'name',

                ['class' => 'yii\grid\ActionColumn'],

            ],

        ]); ?>

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

</div>

<?php

$this->registerJs("$(function() {

   $('.show-modal').click(function(e) {

     e.preventDefault();

     $('#modal').modal('show').find('.modal-body')

     .load($(this).attr('href'));

   });

});", View::POS_READY, '.show-modal');

?>



View _form.php


<?php


use yii\helpers\Html;

use yii\widgets\ActiveForm;

use yii\web\View;


/* @var $this yii\web\View */

/* @var $model app\models\Country */

/* @var $form yii\widgets\ActiveForm */

?>

<?php

$this->registerJs(

   '$("document").ready(function(){ 

        $("#pjax-create").on("pjax:end", function() {

            $.pjax.reload({container:"#pjax-grid"});  //Reload GridView

        });

    });'

);

?>


<div class="country-form">

	<?php yii\widgets\Pjax::begin(['id' => 'pjax-create']) ?>

		<?php $form = ActiveForm::begin(['options' => ['data-pjax' => TRUE]]); ?>


		<?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>


		<div class="form-group">

			<?= Html::submitButton($model->isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>

		</div>


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

	<?php yii\widgets\Pjax::end() ?>

</div>

1 Like

You have a few issues but you are off to a good start.

Controller

You need to make sure you send back server side validation errors. You can also send back data like I show with the message. I send back flash messages this way.

I’d also join the two index functions. It doesn’t make since to separate them because it’s only doing one thing.





public function actionIndex() {

    $searchModel = new CountrySearch();

    $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

    return $this->render('index', [

                'searchModel' => $searchModel,

                'dataProvider' => $dataProvider

    ]);

}


public function actionCreate() {

        $model = new Country();

        if ($model->load(Yii::$app->request->post())) {

            \Yii::$app->response->format = Response::FORMAT_JSON;

            if ($model->save()) {

                //return whatever you need

                return ['message' => 'Successfully added a new  country.'];

            }

            //If model doesn't save sent back server side validation errors

            return ['errors' => \yii\widgets\ActiveForm::validate($model)];

        } else {

            return $this->renderAjax('_form', [

                        'model' => $model

            ]);

        }    }

form

Remove the pjax from the form it is not needed and could cause problems. You need to submit your form via ajax and on success of the form reload the pjax and close the modal.


<?php

use yii\helpers\Html;

use yii\widgets\ActiveForm;

/* @var $this yii\web\View */

/* @var $model app\models\Country */

/* @var $form yii\widgets\ActiveForm */

$form = ActiveForm::begin(['id' => 'countries-form']);

echo $form->field($model, 'name')->textInput();

?>

<div class="form-group">

    <?= Html::submitButton($model->isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>

</div>

<?php

ActiveForm::end();

$this->registerJs("

  //this will work with mulitpart data or regular form

  jQuery('#countries-form').submit(function(e) {

      e.preventDefault();

      jQuery.ajax({

          url: jQuery(this).attr('action'),

          type: jQuery(this).attr('method'),

          data: new FormData(form[0]),

          mimeType: 'multipart/form-data',

          contentType: false,

          cache: false,

          processData: false,

          dataType: 'json',

          success: function(data) {

              //if there are serverside errors then ajax show them on the page

              if (data.errors) {

                  jQuery.each(data.errors, function(key, val) {

                      var el = jQuery('#' + key);

                      el.parent('.form-group').addClass('has-error');

                      el.next('.help-block').html(val);

                  });

              } else {

                  //reload pjax and close boostrap modal

                  jQuery.pjax.reload({

                      container: '#countries'

                  });

                  jQuery('#modal').modal('hide');

              }

          }

      });

      return false;

});");



in your index should be something like the following. Please note you will need to follow this wiki I wrote for your boostrap modal to load the form via ajax




<?php


use yii\helpers\Html;

use yii\grid\GridView;

use yii\widgets\Pjax;

use yii\helpers\Url;


/* @var $this yii\web\View */

/* @var $searchModel app\models\CountrySearch */

/* @var $dataProvider yii\data\ActiveDataProvider */


$this->title = Yii::t('app', 'Countries');

$this->params['breadcrumbs'][] = $this->title;

?>

<h1><?= Html::encode($this->title) ?></h1>

<?php

echo Html::a(Yii::t('app', 'Create Country'), FALSE, ['value' => Url::to(['countries/countries/create']), 'class' => 'btn btn-success showModalButton']);

Pjax::begin(['id' => 'pjax-grid']);

?>

<div>Current Time: <?= date('Y/m/d H:i:s') ?></div>

<?=

GridView::widget([

    'dataProvider' => $dataProvider,

    'filterModel' => $searchModel,

    'columns' => [

        ['class' => 'yii\grid\SerialColumn'],

        'id',

        'name',

        ['class' => 'yii\grid\ActionColumn'],

    ]

]);

Pjax::end();



I haven’t tested anything and wrote it on the fly so there might be a couple typeos. Just check your console and yii’s debug toolbar for any errors. Let me know if you have issues