Yii2: Refreshing Listview inside modal dialog using Pjax

Created on 8 Jul 2015  路  20Comments  路  Source: yiisoft/yii2

I have a Listview that is rendered inside a modal dialog:

<?php Pjax::begin([
    'id' => 'image-list',
    'timeout' => Yii::$app->params['timeout'], 
    'enablePushState' => false        
]); ?>

        <?= ListView::widget([
            'dataProvider' => $dataProvider,          
            'options' => ['class' => 'list-view'],          
            'itemView' => function ($model, $key, $index, $widget) {
                $path = $model->getImage();
                $size = $model->getImageSize(100, 'H');

                return Html::a(Html::img($path, [
                        'width' => $size['width'],
                        'height' => $size['height'],
                    ]), $path).
                    Html::a('<i class="glyphicon glyphicon-trash"></i>', '#', [
                        'class' => 'arr-img pull-left',
                        'title' => 'Delete',
                        'onclick' => "
                            if (confirm('Are you sure you want to delete this image?') == true) {                            
                                $.ajax({            
                                    type: 'POST',
                                    cache: false,
                                    url: '" .Yii::$app->urlManager->createUrl(['arrangement-image/delete', 'id' => $model->id]). "',
                                    success: function(response) {
                                        $.pjax.reload({container: '#image-list', timeout: " .Yii::$app->params['timeout']. "});
                                    }
                                });
                            }

                            return false;
                        "
                    ]);
            },
        ]) ?>

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

That Listview is rendered via ajax request:

'image' => function ($url, $model) {
    return Html::a('<i class="glyphicon glyphicon-picture"></i>', '#', [
         'title' => 'View Images',
          'onclick' => "
               $('#image-modal').modal('show');

               $.ajax({            
                  type: 'POST',
                  cache: false,
                  url: '" .Yii::$app->urlManager->createUrl(['arrangement-image/index', 'id' => $model->id]). "',
                  success: function(response) {
                        $('#image-modal .modal-body').html(response);
                  },
              });

              return false;
       ",
  ]);                            
}

The data loading and pagination work fine, but when I tried to refresh Listview using $.pjax.reload, the whole page was refreshed and modal dialog was closed. This doesn't happen when I render the Listview without modal dialog.

There are other people (Thread 1, Thread 2) who have ever posted about this topic. Unfortunately, there is not a specific solution for this as far as I can see. How to refresh Listview inside modal without refreshing the whole page?

pjax to be verified

All 20 comments

hi @re1naldo did you solve this problem??

@cocuba Unfortunately, no.

I guess it may occur because pjax update removes the modal dialog's DOM

I have the same problem!
Is there already solution for this?

Is your modal located inside of the PJAX container, that you are trying to refresh?

No the modal is in main.php in layouts.

Like this.

'clientOptions' => ['backdrop' => 'static', 'keyboard' => false],
'options' => [
'id' => 'modalDialog',
],

<div id='modalContent'></div>

<?php yii\bootstrap\Modal::end() ?>

Could you isolate the problem and offer easy steps to reproduce it, please?

sure.
This is a bit of cleaned up code

The dialog is called by a js function.

 $('#modalDialog')
            .modal('show')
            .find('#modalContent')
            .html(data);

In my controller I call.

 return $this->renderAjax('mailJobs', [
        'dataProvider' => $provider,
    ]);

in my view 'mailJobs'

<?php
use yii\widgets\ActiveForm;
use yii\grid\GridView;
use yii\widgets\Pjax;

<?php Pjax::begin([
    'id' => 'image-list',
    'timeout' => 2000, 
    'enablePushState' => false        
]); ?>

<?php $form = ActiveForm::begin([
    'id' => $model->formName().'-form',
]);
?>

<?= Html::input('text', 'data[operator]', '', ['class' => 'form-control', 'id' => 'operator']); ?>

<?= GridView::widget([
    'id' => 'calendar_grid',
    'dataProvider' => $dataProvider,
    'columns' => [
        'product',
        'title',
    ],
]); ?>

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

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

<?php
$script = <<< JS

$(document).on('click', '#operator', function(e){
    $.pjax.reload({container:'#image-list'});
});

JS;
$this->registerJs($script);

The grid is refreshing, and after that the model will close.

It looks like a total reload of the website, after refreshing the gridview.

It seems to be working when adding these options:

$.pjax.reload({container:'#calendar_grid-3', url:'/calendar/email_jobs', replace:false});

I guess it may occur because pjax update removes the modal dialog's DOM

So my guess was truley? :)

It seems to do a reload from url:'/' without these options
Only in a modal.

I just had a kind of similar issue to @hdewaart. everything worked fine until adding this column to gridview:

[
    'attribute' => 'required',
    'format' => 'html',
    'value' => function ($model, $key, $index, $column) {
        return $model->required ? '<span class="fui-check"></span>' : '';
    }
],

I find out that when removing 'format' => 'html' it worked back again (I mean without page refresh). so I added this:

$('#attribute-list').on('pjax:error', function (event, error) {
    console.log('pjax:error',error.statusText)
    event.preventDefault();
});

which says that it is a timeout issue. I guess it is expected when the gridview gets heavy. the problem is when I did set a bigger timeout within php (Pjax::begin(['id' => 'attribute-list', 'timeout' => 5000])) it didn't solve it. I can see the data-pjax-timeout and its related jquery code injected correctly into view:

<div id="attribute-list" data-pjax-container="" data-pjax-push-state data-pjax-timeout="5000">
jQuery(document).pjax("#attribute-list a", "#attribute-list", {"push":true,"replace":false,"timeout":5000,"scrollTo":false});

but when digging into the jquery.pjax.js code by putting breakpoints here I see the timeout value set to 650 which is it's default value as shown here but different from my 5000 config or the 1000 set by default within the PHP widget here.

I don't know much about pjax or if this is expected or just a bug. Currently my code is just working fine without any page refresh after setting the timeout value within javascript:

$.pjax.reload({container: container, timeout: 1200})

so what do you think @SilverFire ? is this expected ? does $.pjax.reload() use a different timeout value than the one already set by default ? or may it be the bug ?

I may be wrong but I suspect $.pjax.reload() not using the correct settings but the built-in default ones instead which may also explain @transitmedia fix https://github.com/yiisoft/yii2/issues/9040#issuecomment-171631715

Yes, it could be so. Could possibly be verified by logging settings and checking if these match default ones.

here is a minimal example to reproduce it in a view file:

<?php
use yii\widgets\Pjax;
use yii\grid\GridView;
use yii\data\ArrayDataProvider;

 /* 
      1 sec is enough to trigger the timeout error as it is set to 0.650 
      even if a different value is set via php.
 */
sleep(1);
?>

<button onclick="$.pjax.reload({container:'#pjax'});">reload pjax</button>
<pre id="output"></pre>

<?php Pjax::begin(['id'=>'pjax', 'timeout'=> 999999999 ]); ?> 
    <?= GridView::widget([
        'dataProvider' => new ArrayDataProvider(['allModels'=>[['name'=>'bob','age'=>rand(10,80)]]]),
        'columns' => ['name','age'],
    ]); ?>
<?php Pjax::end(); ?>

<?php
$this->registerJs(<<<JS
$('#pjax').on('pjax:error', function (event, error) {
     $('#output').append('pjax:error.statusText: ' + error.statusText + '<br>')
     event.preventDefault();
 });
JS
);
?>

Note: $.pjax.reload({container:'#pjax', timeout: 2000}) should solve it and the error won't trigger.

pjax scope

pjax scope

@dynasource how? please check my minimal example above. it is about the php widget itself:

<?php Pjax::begin(['id'=>'pjax', 'timeout'=> 999999999 ]); ?> 

this property is just useless as it won't change the library's default 0.65 sec to 1 sec or any other value. I think that is causing most of the pjax refreshing issues. I guess it is not related to modals or gridviews or other stuff, just any page getting heavier to be loaded in less than 0.65 sec.

because you are using $.pjax.reload(). This is the pjax scope as you can see:

The time out in the Yii widgets works correctly for clicks & submission within the Pjax container. However, if you use Pjax functions like $.pjax.reload, then you loose original configurations set by Yii.

Is this optimal? No. But its out of Yii's scope.
Must say, because of issues like this, we are going to drop Pjax in the future but for now we have to deal with its shortcomings.

ok that makes sense. thanks for explanations and welcome to Yii :+1:

Was this page helpful?
0 / 5 - 0 ratings