Ajax / Registerclientscript

I often have problems with widgets/js-code inside a ajax-environment (pager in CListView …).

The problem is, that the (most of all) widgets use ‘clientScript->registerScript’ to publish the js-code.

But this will not work in a ajax-response and the script will not be executed.

And (perhaps?) globally registered jQuery functions cannot be used in the ajax response (needs more investigation…).

Also the CHtml::clientChange uses ‘registerScript’ and I have sometimes problems with that.

The problem is similar to renderPartial, with processOutput=false.

If I work with my own ajax-response controllerAction, this is no problem, but the problem are the widget extensions.

In most cases I can override the widgets registerClientScript method like below and it works:




class MyAjaxReadyWidget extends SomeWidget

{

    public $directOutput = null; //= autoMode: check for ajax




    public function init() 

    {

        if($this->directOutput == null)

            $this->directOutput=Yii::app()->request->isAjaxRequest; 


        parent::init();

    }


    public function registerClientScript()

    {

        if($this->directOutput)

        {

           $jsScript = ... nearly the same as in the parent ...

           echo CHtml::script($jsScript );

        }

        else

            parent::registerClientScript();

    }






Am I missing another solution for that problem?

I would like to see a workaround for this problem in the core.

  1. place libraries/functions in the main view (jQuery,…) that can be used in the ajax-response.

  2. a ‘directOutput’ feature in the core CWidget that processes the js-code immediatly in the run() method.

Maybe it should be possible to ‘register’ scripts in the ClientScript for ‘directOutput’ too, not only the current ‘registerScript’.

Indeed. Registered scripts are rendered when the whole page renders. Since with AJAX you’re modifiying just a little piece of HTML, even if your AJAX response has <script> tags on it, the browser won’t execute them and they won’t be rendered.

The first solution is what I use, but the second would be preferred.

Maybe a possible solution could be to add methods to the base CWidget class like

  • registerScript($script)

  • registerScriptFile($scriptFile)




class CWidget extends extends CBaseController

{

    public $directOutput = false;


    public function registerScriptFile(script) 

    {

       if ($this->directOutput)

         echo CHtml::scriptFile($script); 

       else

          Yii::app()->getClientScript()->registerScriptFile(script);

    }    




and the widget can add the scripts in the init() or run() method like




  public function init() //or run()

  {

    ...

    $this->registerCoreScript('jquery');

    $this->registerScriptFile($assets.'fancybox.js');

    ... 


  }




Mabe a similar solution can be added to CClientScript …

I’m currently working on a fancybox widget that should work inside a CListView - not only on the first page.

And it works now with ‘directOutput’=>true :slight_smile:

Coming soon as addon to my ‘quickdlgs’ extension.

I don’t want to stop the discussion here, because in my opinion this is a unsolved problem of the Yii core.

It’s a general problem, that widgets / core-widgets cannot be used together with a CListView.

Will this be solved in Yii 2.0 ?

Copy/Paste example:

Try to use CJuiDialog inside a CListView




$items = array();

$items[] = array('id'=>1,'content'=>'Item 1');

$items[] = array('id'=>2,'content'=>'Item 2');

$items[] = array('id'=>3,'content'=>'Item 3');

$items[] = array('id'=>4,'content'=>'Item 4');

$items[] = array('id'=>5,'content'=>'Item 5');


$dataProvider = new CArrayDataProvider($items, array(

    'keyField'=>'id',

    'pagination'=>array(

        'pageSize'=>2,

    ),

));




$this->widget('zii.widgets.CListView', array(

    'dataProvider'=>$dataProvider,

    'itemView'=>'_detail',   // refers to the partial view named '_post'

));




_detail view:




<div>

<?php

$this->beginWidget('zii.widgets.jui.CJuiDialog', array(

    'id'=>'mydialog'.$data['id'],

    // additional javascript options for the dialog plugin

    'options'=>array(

        'title'=>'Dialog box 1',

        'autoOpen'=>false,

    ),

));


echo $data['content'];


$this->endWidget();


// the link that may open the dialog

echo CHtml::link('open dialog', '#', array(

    'onclick'=>'$("#mydialog'.$data['id'].'").dialog("open"); return false;',

));

?>

</div>



This only will work on the first page …

I have tried to solve the problem with the fancybox addon in the extension quickdlgs 2.0.

It work’s but I don’t like this ‘hack’ … :frowning:

I don’t get your problem…

Why not use a renderPartial(’_view’, array(‘model’=>$model), false, true) ?

Where to use renderPartial in the example above?

this will not run dialog initialisation when inserted with ajax.