скрипт дублируется, если использовать renderPartial несколько раз (ajax)

Есть форма с двумя кнопками


echo CHtml::button('button',array('id'=>'qwer'));

echo CHtml::ajaxButton('load_script',$this->createUrl('/test/test'),array(

            'update' => '#test',          

            'cache' => false,

           ));

в экшене test :


$this->renderPartial('_testview', array(),false,true);

в _testview:


Yii::app()->clientScript->registerScript('#script',

   '$("body").undelegate("#qwer","click").delegate("#qwer","click",function(){alert("1");})');

Yii::app()->clientScript->registerScript('#script',

   '$("body").undelegate("#qwer","click").delegate("#qwer","click",function(){alert("2");})');



два скрипта - проверял undelegate вообще работает или нет - работает второй скрипт выключает первый, но не выключает второй, который был загружен прошлый раз. После нажатия кнопки ‘load_script’ количество alert(“2”), навешанных на кнопку ‘button’ увеличивается на единицу. Я предполагал что undelegate("#qwer",“click”) удалит все обработчики.

В реальной задачи вместо скрипта с алертом еще несколько CHtml::ajaxButton, но yii генерирует такой же код с '$(“body”).undelegate("#qwer",“click”).delegate("#qwer",“click”,function(){…}) и они тоже дублируются.

версия Yii 1.1.7 (Mar 26, 2011)

Подскажите, пожалуйста, как с этим бороться?

Если правильно понял, то следует отключать генерацию скрипта при аякс запросе (ну или генерировался только один раз) - без контекста не совсем понятно.

Но после выполнения обновиться DOM, по этому, что бы существующие скрипты работали с обновленным деревом нужно их события биндить через live().

По моему как-то так.

Контекст: на странице есть корзина товаров и поле для поиска товара, после поиска загружается табличка с найденными товарами (ajax), название, изображение и кнопка "добавить в корзину", если поискать тот же товар, то при втором нажатии на "добавить в корзину" он добавится дважды, в третий раз - трижды.

Если я отключу скрипт в аякс запросе, то кнопка "добавить" не сработает, если один раз - то при поиске следующих товаров отрабатываться не будет, а через live() я не знаю заранее какой товар будет искаться и, соответственно, к какому id привязываться…

Напрямую к вопросу это не относится, но здесь два раза вызывается registerScript(’#script’, …) с одним и тем же значением первого параметра - ‘#script’, соответственно первый скрипт “отключается” еще на сервере, так как второй registerScript с тем же ID скрипта перекрывает первый.

А по поводу проблемы - может здесь лучше использовать bind? Тогда при замене старого куска HTML новым, старые обработчики тоже будут удаляться.

Вместо undelegate/delegate? но я же не в ручную эти скрипты пишу, в первом посте упростил как мог, что бы возможно было повторить проблему… а вообще через аякс->renderPartial выводится табличка:


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

	    'dataProvider'=>$dataProvider,

            'columns'=>array(

                array(

                    'name' => 'title',

                    'type'=> 'raw',

                    'value' => '$data->title_rus?$data->title_rus." / ".$data->title:$data->title',

                ),

                ...

                array(

                    'name' => 'action',

                    'type' => 'raw',

                    'id' => '$data->id',

                    'value' => 'CHtml::ajaxButton("add",array(

                            "/order/add",

                            "id"=>$data->id,

                            "order_id"=>'.$order_id.'

                        ),array(

                            "update"=>"#loadorder",

                            "complete" => "js:$(\"#search\").html(\"\")",                          

                        ),array(

                            "id"=>$data->id,

                            "name"=>"add"

                        )

                    )',

                )

            ),

        ));

и вот эта ajaxButton("add"… скрипт к которой вешается через delegate отрабатывает дважды, трижды, сколько раз загрузится. Как его под bind переделать не испортив ничего я не знаю. Может вообще я что то не то делаю и есть другая, более правильная реализация тех действий, что я прошлом посте написал?

Попробуйте в параметр $htmlOptions добавить ‘live’=>false




 'value' => 'CHtml::ajaxButton("add",array(

                            "/order/add",

                            "id"=>$data->id,

                            "order_id"=>'.$order_id.'

                        ),array(

                            "update"=>"#loadorder",

                            "complete" => "js:$(\"#search\").html(\"\")",                          

                        ),array(

                            "id"=>$data->id,

                            "name"=>"add",

                            "live"=>false,  <------------ в параметр $htmlOptions добавить 'live'=>false

                        )

                    )',



Или вот еще посмотрите - http://www.yiiframework.com/wiki/178/how-to-avoid-multiple-ajax-request/.

А по сути все-таки не совсем понятно, почему старые обработчики остаются.

По идее undelegate().delegate() от этого как раз и защищает.

Я сейчас попробовал воспроизвести, зашел на jquery.com, в консоли Firebug выполнил




$("body").undelegate("#jq-intro","click").delegate("#jq-intro","click",function(){alert("1");})



Где #jq-intro - это первый абзац текста - "jQuery is a new kind of JavaScript Library…".

Сколько бы раз я не запускал приведенный выше кусок кода, alert выводится только один раз.

seb, "live"=>false помогло! спасибо большое.

Я не пробовал без использования yii загружать подобный код через ajax (если будет работать, получается баг yii, но не проверив не стал так заявлять), а если на одной и той же странице делать undelegate().delegate(), то да все работает как и ожидается.