anon
anon

Reputation:

Pjax keeps refreshing whole page in Yii2, Pjax is called multiple times inside listview

I have been trying to resolve this issue in these few days, basically i am trying to have commetn and child comments, the comment has a button/link called 'retrievecomment' to retrieve child comment.

I found out that The pjax is not working, it keeps refreshing the whole page.

    <div class="row">   
            <?= $model['comment']?>
    </div>
    <div class="row">
        <div id="selector"align="right">
            <?= Html::a('Retrieve Comment', ["../../thread/index?id=" . $model['thread_id'] . "&comment_id=" . $comment_id], 
                                        ['data-pjax' => '#childCommentData-'.$comment_id, 'class' => 'btn btn-default'
                                        ,'id' => 'retrieveComment' . $comment_id]) ?>
        </div>

        <?php Pjax::begin([
            'id' => 'childCommentData-'.$comment_id,
            'clientOptions'=>[
                    'timeout' => 5000,
                    'registerClientScript' => "$.pjax.reload({container:'#childCommentData-$comment_id'});",
                    'linkSelector'=>'#retrieveComment'.$comment_id
                    ]
            ]);?>

            <div  class="col-md-12">

                <?php if(isset($retrieveChildData)){ ?>
                    <?= ListView::widget([

                            'dataProvider' => $retrieveChildData,
                            'options' => [
                                'tag' => 'div',
                                'class' => 'list-wrapper',
                                    'id' => 'list-wrapper',
                            ],
                                'layout' => "\n{items}\n{pager}",

                            'itemView' => function ($model, $key, $index, $widget) {
                                return $this->render('_list_child_comment',['model' => $model]);
                            }, 
                            'pager' => [
                                'firstPageLabel' => 'first',
                                'lastPageLabel' => 'last',
                                'nextPageLabel' => 'next',
                                'prevPageLabel' => 'previous',
                                'maxButtonCount' => 3,
                            ],
                        ]) ?>

                <?php } ?>


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

</div>

The Pjax for the comment is called multiple times inside the listview , i believe this has become the problem since the compiler confused which pjax to be reloaded,

Controller code (inside actionIndex)

            else if(!empty($_GET['comment_id'])){
                $comment_id = $_GET['comment_id'];

                //retrieve yes data
                $retrieveChildData = new SqlDataProvider([
                    'sql' => Comment::retrieveChildComment($comment_id),  
                    'totalCount' => Comment::countChildComment($comment_id),
                    'pagination' => [
                        'pageSize' =>5,
                        ],

                ]);
                return $this->render('_list_comment.php', ['retrieveChildData' => $retrieveChildData]);

            }

Upvotes: 3

Views: 2883

Answers (1)

PLM57
PLM57

Reputation: 1296

Most common problem-Sources

Usually the whole-page-refresh of pjax has two possible sources:

  1. Your pjax-request exceeds the timeout set in the pjax settings. This leads to a full page-refresh
  2. You trigger another pjax-request before your first one finished which also leads to a full page-refresh, as pjax does not support multiple parallel refreshes

How to solve #1

This one is easy and it looks like you figured it out yourself already. You only have to increase the pjax-timeout value. You can do this on each widget-instance individually or just set it globally like this:

if ($.pjax) {
    $.pjax.defaults.timeout = 5000;
}

The code above sets the default timeout for all pjax-instances to 5000ms. Usually more than enough. The usual default value of 650ms is rather tight for complex web-applications.

You can find all options on the official site: here

How to solve #2

This is a bit trickier and it looks like this is your problem here. To find out, look at your debug toolbar and make sure you preserve the log accross pages (in chrome this settings name is preserve log under the network tab. If you see multiple requests fire, this is your problem!

If so, you have to first implement your own check to ensure no additional pjax request fires while there still are some running. If you don't and a user clicks two buttons fast after each other you'll run into this no matter what.

I usually prevent this by implementing a counter of how many ajax requests are running. If the counter is 0 I trigger the new request, otherwise i'll wait.

Example for an ajax-counter:

//this is the actual counter
var ajaxCounter = 0;

//this method is called whenever an ajax-request fires
$(document).ajaxSend(function() {
    ajaxCounter++;
});

//this method is called whenever an ajax-request finishes...no matter of its result
$(document).ajaxComplete(function() {
    ajaxCounter--;
});

//check if pjax calls are allowed right now
var pjaxAllowed = function () {
    return ajaxCounter == 0;
}

Et voilà! Before you trigger your pjax you simply check if ajaxCounter == 0 or use the convenience-function pjaxAllowed() as shown above. If you don't want to check this each and every time you could implement your own little pjax-request-stack. Doing so is very easy with the events pjax provides: Pjax-Events

I hope I could help you out. This one gave me some headaches as well ;)! If you need some more infos just let me know...

Common pjax debugging

  • The debug-toolbar is your friend. Make sure preserve logs within the network tab of the dev tools of Chrome is checked. Otherwise you lose track of the requests when the page gets reloaded
  • If you see a request beeing aborted, then usually this indicates problem @2 from above
  • If you see a request returning something else than HTTP-code 200, then check the preview of the response in the dev-tools of Chrome. Usually this shows you the exception occured. In this case your problem is on the server-side. Double check your php-code and fix it!
  • Links within a pjax-container are treated specially. If you want them to trigger a refresh of the surrounding pjax-conatiner, leave them as is...otherwise add the attribute data-pjax="0" to them. This indicates that no refresh is desired if this link is clicked.
  • read the doc...its 5 minutes well spent: https://github.com/defunkt/jquery-pjax

Upvotes: 7

Related Questions