Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TbExtendedGridView causing "Maximum call stack size exceeded" with options.success #430

Closed
xloading opened this issue Mar 31, 2013 · 4 comments
Labels
Milestone

Comments

@xloading
Copy link

Hi Antonio and All,

First of all I would like to thank you for such a great work on YiiBooster. It became really a de facto standard for development of Yii+Bootstrap projects.

Coming to the issue that I would like to discuss as stated in the subject it relates to TbExtendedGridView functionality.
Here is how my interface look like (sorry, menus are in Russian):
grid
Menu on the left is a set of AJAX links stored in _menubystatus view:

<div id='reviewmenubytype'>
<ul>
    <li><?php echo CHtml::ajaxLink(
        Yii::t('menuItems','Pending reviews'),
        array('/admin/productfeedback/adminbystatus', 'status'=>Productfeedback::STATUS_PENDING),
        array('update' => '#reviews',

        ),
        array(
            'id'=>uniqid()
        )
    );?></li>
    <li><?php echo CHtml::ajaxLink(Yii::t('menuItems','Approved reviews'), array('/admin/productfeedback/adminbystatus',
        'status'=>Productfeedback::STATUS_APPROVED),
        array('update' => '#reviews',
          ),
        array(
            'id'=>uniqid()
        ));?></li>
    <li><?php echo CHtml::ajaxLink(Yii::t('menuItems','Rejected reviews'),
        array('/admin/productfeedback/adminbystatus', 'status'=>Productfeedback::STATUS_REJECTED),
        array(
            'update' => '#reviews',

        ),
        array(
            'id'=>uniqid()

        ));?></li>
</ul>
</div>
<div id='reviewdetails'>
<div id='reviewactions'></div>
<div id='reviews'></div>
</div>

As you can see upon clicking on the items of this list action AdminByStatus in productfeedback controller is executed and it's result is placed into #reviews div. The action is quite simple:

public function actionAdminByStatus()
    {
        if(isset($_GET['status']))
        {
            //$reviews = Productfeedback::model()->findAllByAttributes('status'=>$_GET['status']);
            $dataProvider=new CActiveDataProvider('Productfeedback',array(   
                    'criteria'=>Array(
                        'select'    =>'t.id,user.email as user_email,t.status,product.name as product_name,t.feedback,t.image01,t.image02,t.image03,t.paidflag',
                        'with' => array('user','product'),
                        //'join'      =>' JOIN  `productcategory` productcategory ON  `product`.`categoryid` =  `productcategory`.`id`',
                        'condition' => 't.status = IFNULL('.$_GET['status'].',0)',
                        ),
                    )
            );

            $this->renderPartial('_adminbystatus',array(
                'dataProvider'=>$dataProvider,
                'status' => $_GET['status'],
            ),false,true);
        }
    }

And _adminbystatus view contains only the TbExtendedGridView actually:

/* @var ProductfeedbackController $this */

$this->widget("bootstrap.widgets.TbExtendedGridView", array(
    'id' => 'feedBacks',
    'dataProvider' => $dataProvider,
    'bulkActions' => array(
        'actionButtons' => array(
                array(
                    'buttonType' => 'button',
                    'type' => 'success',
                    'size' => 'small',
                    'label' => 'Bulk Approve',
                    'click' => 'js:function(checked){
                                     var ids = new Array();
                                     checked.each(function(){
                                         ids.push($(this).val());
                                     });
                                     $.ajax({
                                         type: "POST",
                                         url:"'.Yii::app()->createUrl("/admin/productfeedback/bulkapprove").'",
                                         data: {"ids":ids},
                                         dataType:"json",
                                         success:function(data){
                                             // update the grid now
                                             $("#'.$grid_id.'").yiiGridView("update");
                                         }
                                         });

                    }',
                ),
                array(
                    'buttonType' => 'button',
                    'type' => 'danger',
                    'size' => 'small',
                    'label' => 'Bulk Reject',
                    'click' => 'js:function(checked){
                                     var ids = new Array();
                                     checked.each(function(){
                                         ids.push($(this).val());
                                     });
                                     $.ajax({
                                         type: "POST",
                                         url:"'.Yii::app()->createUrl("/admin/productfeedback/bulkreject").'",
                                         data: {"ids":ids},
                                         dataType:"json",
                                         success:function(data){
                                             // update the grid now
                                             $("#'.$grid_id.'").yiiGridView("update");
                                         }
                                         });

                    }',
                )
            ),
            // if grid doesn't have a checkbox column type, it will attach
            // one and this configuration will be part of it
            'checkBoxColumnConfig' => array(
                'name' => 'id'
            ),
    ),
    'columns' => array(
        'user.email',
        'product.name',
        'feedback',
        array('type' => 'image',
            'name' => 'Image1',
            'value' => '"/images/productreviews/$data->id/thumbs/$data->image01"',
            'headerHtmlOptions' => array('width' => '100px'),
        ),
        array('type' => 'image',
            'name' => 'Image2',
            'value' => '"/images/productreviews/$data->id/thumbs/$data->image02"',
            'headerHtmlOptions' => array('width' => '100px'),
        ),
        array('type' => 'image',
            'name' => 'Image3',
            'value' => '"/images/productreviews/$data->id/thumbs/$data->image03"',
            'headerHtmlOptions' => array('width' => '100px'),
        ),
        array(
            'header' => "Options",
            'type' => 'raw',
            'value' => function ($data, $row) {
                /* @var Productfeedback $data */
                switch ($data->status) {
                    case Productfeedback::STATUS_REJECTED:
                        echo CHtml::ajaxLink(CHtml::image(Yii::app()->request->baseUrl . '/images/approve.png'),
                            Yii::app()->createUrl("/admin/productfeedback/approve", array("id" => $data->id)),
                            array(
                                'type' => 'POST',
                                'dataType' => 'json',
                                'success' => '
                        function(res){
                            if(res.status==="success"){
                            $.fn.yiiGridView.update("feedBacks");
                            }

                        }'
                            ),
                            array(
                                'id' => uniqid()
                            )
                        );
                        break;
                    case Productfeedback::STATUS_APPROVED:
                        echo CHtml::ajaxLink(CHtml::image(Yii::app()->request->baseUrl . '/images/delete.png'),
                            Yii::app()->createUrl("/admin/productfeedback/reject", array("id" => $data->id)),
                            array(
                                'type' => 'POST',
                                'dataType' => 'json',
                                'success' => '
                        function(res){
                            if(res.status==="success"){
                            $.fn.yiiGridView.update("feedBacks");
                            }

                        }'
                            ),
                            array(
                                'id' => uniqid()
                            )
                        );
                        break;
                    default:
                        echo '3 '.$data->status;
                        break;
                }


            },

        ),
        array(
            'header' => 'Options',
            'class' => 'EButtonColumn',
            'template' => '{view}{update}{approve}{reject}',
            'buttons' => array(
                'view' => array(
                    'icon' => 'view',
                    'label' => 'View',
                    'url' => 'Yii::app()->createUrl("/admin/productfeedback/view", array("id"=>$data->id))',
                    'click' => $viewDialog,
                    'options' => array(
                        'id' => uniqid()
                    )
                ),
                'update' => array(
                    'icon' => 'update',
                    'label' => 'Update',
                    'url' => 'Yii::app()->createUrl("/admin/productfeedback/update", array("id"=>$data->id))',
                    'click' => $updateDialog,
                    'options' => array(
                        'id' => uniqid()
                    )
                ),
            ),
        ),
    )
));

As you can see there are also AJAX buttons in the grid which allow me to approve/reject the reviews and update the grid upon successful execution.

Unfortunately the problem is that after some multiple movements between the different menu items (e.g. Pending Reviews, Approved Reviews) clicking approve/reject AJAX buttons in the grid causes Firefox to hang and Chrome to put the following info in the console during the grid update:
chrome_console

After some digging I found out that the problem is specifically in the method registerCustomClientScript of TbExtendedGridView as everything behaves correctly in TbGridView. Also adding console.log into the following piece of JS code allowed me to find the infinite loop there after the same grid is loaded twice or more:

if(qs.hasOwnProperty("ajax") && qs.ajax == "' . $this->id . '")
                {
                    options.realsuccess = options.success;
                    options.success = function(data)
                    {
                        //console.log("We are here2!");
                        if(options.realsuccess) {
                            options.realsuccess(data);

Unfortunately I'm not good at JQuery/JS myself therefore I can't figure out the way to resolve this issue.

Please let me know if any additional clarifications are needed and thank you very much in advance for the help!

@xloading
Copy link
Author

In order to simplify the illustration I've created sandbox on my server:
http://sandbox.xloading.net/productfeedback/menubystatus

The sequence of actions is: go to Approved Reviews, reject the review presented there, go to Rejected Reviews and try to approve it - here the problem comes out.

@xloading
Copy link
Author

xloading commented Apr 4, 2013

Hi Clevertech team,

Have I provided enough information for this problem? Is there something unclear about the bug nature?

Thank you in advance for the help!

@hijarian
Copy link
Contributor

hijarian commented Apr 6, 2013

@xloading Man, you're just awesome. So much info for a bug is a rare find. We don't have Antonio among the developers anymore. I'm a current maintainer of YiiBooster for now. I'll look into this bug for sure.

@digitalcrab
Copy link
Contributor

Hello @xloading
Seems that I fixed this issue in current branch, and it will be included in the next release (17-18 of Dec 2013)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants