Dublicate live event handlers on ajax

Discussion for the issue - http://code.google.com/p/yii/issues/detail?id=2981

First problem that I see here is the "global" converting of all <a href=""> links to ajax calls

index.php has this code :


if(!Yii::app()->request->isAjaxRequest) 

	Yii::app()->clientScript->registerScript('ajax_links',

	'$("a").live("click",function(e){

		if(e.isDefaultPrevented())

			return;

		$this=$(this);

		if(!$this.attr("noajax")){

			$("#content").load($this.attr("href"));

			return false;

		}

		})

	');?>

By this code… after clicking any link the browser instead of loading the new page… it makes an ajax call and it replaces the #content with the returned result…

That code is in the first place the reason why the delete action of the CGridView is duplicating on every ajax call…

try without it and the CGridView will work as intended (without undelegating or changing any Yii core)…

try to echo something in the actionDelete like echo "deleted"… and you will see the obvious problem… as the word "deleted" will replace the #content

one more thing… this code does a GET request while the actionDelete expects a POST request… and the worst problem is that first this request is executed… and then the default delete request… (check with firebug breakpoints)

As author of the issue i can help with testing. I mean more bugs and nuances. Sorry for my english. I can only speak in "plain english".

P.S.: thanks for helping.

If event by grid view was sending and preventing the live event handler wouldn’t throw.

The problem is in the JS code in index.php… it fires two ajax events even on first load of the page… check with firebug…

It is only the example of ajax application. And the problem presents only in ajax applications. I can’t drop ajax supporting for reporting the issue because of that.

I understand that the problem happens only on ajax applications… but the aajx call can be made in many different ways… for example you are here replacing the complete #content every time… the optimised ajax application would replace just the element that is intended by that link…

for example the CGridView links are replacing only the grid itself… not the whole #content / page…

So… as I wrote above… the first problem why the delete button is duplicating is that custom JS code… and for that part there is nothing to be solved in Yii… it should be solved on the user side… for example by not binding all links to that event… but only custom one…

Please see the render method implementation and follow over instructions.

yes, we will come to that… I just wanted to go in steps… and solve it one by one…

This part of hadler check for only links than not prevented by over js code. The example code is more simple and is not an ideal. But tthis happens each time when i try to reload the page over ajax (by click on the menu’s home link so it is not necessarily to use an pagination).


                if(e.isDefaultPrevented())

                        return;

As I can see, the only significant part is


$("#content").load($this.attr("href"));

that loads content via ajax and does nothing more. All other code doesn’t look like it affects execution since


if(e.isDefaultPrevented())

prevents processing event.

Did you two check this with firebug at all ?

read again my comment #2… did you two try to just echo a word in actionDelete() ?

As I wrote before (and I don’t like to repeat myself)… the problem is that when you click on “delete” button (that is a link)… two ajax calls are made !!!

NOTE: I wrote two ajax calls are made… I did not say two confirm dialogs appears !!!

That happenes even without pagination or click on home…

So that is the first thing that should be fixed, do you agree on that?

Please try at first other tests (not gridview). With gridview i need more time to explain the problem because there are many nuances in it. So as your can see in other tests the main problem is only in not undelegating live events in yii scope before delegating and in cgridview also.(It’s hard to explain more understandably). All other moments i can solve alone.

OK

Let’s go to the other test…

Here the problem is that an event is "live" binded on every ajax call… to solve this… you just need to turn off the live binding like:




	<?php echo EHtml::link('Click me','#',array(

		'return'=>true,

		'confirm'=>'Select yes to test me',

		'noajax'=>true,

		'live'=>false

	));?>



Note that in the Ehtml::clientscript the line


$cs->registerScript('Yii.CHtml.#' . $id, "jQuery('#$id').unbind('$event').bind('$event', function(){{$handler}});");

makes no sense, and should be


$cs->registerScript('Yii.CHtml.#' . $id, "jQuery('#$id').bind('$event', function(){{$handler}});");

Please see FHtml realisation :) It works perfect ;)

EHtml is special buggy class. So, in very big project hard to control all CHtml::clientChange moments(like ajaxLink and another methods. In that fact I use the simplest way to explain the main ploblem with events). I still not sure with CGridView, so your can be right. But it’s need more time to test CGridView and jq realization with live(and also specials) events.

I know that also mini problems presents in global link handler but it does not matter.

Yes, I saw the FHtml… but my point is that this is not needed at all…

in the first place if you dont use ajax… .why call die()/unbind() at all - (consider that few users create completely ajaxed webpages)…

My point is that if that would be the solution… don’t you think that the jQuery team would add that automaticaly to the bind() / live() method ?

I would like to solve this ajax loading issue once for all… that’s why I asked for the user code… working examples… use cases… so to find the solution to every possible case… as my point is that all can be solved by proper user code… but when I give you a solution / idea… at least try it and check if it works for you…

Have you tried my solution?

If you reload the whole page (block content) every time… than all the events on that page / block do not need to be "live" binded at all…

Is there a reason why do you want to "live" bind them every time and then unbind/bind them on every ajax page/conten load ?

I guess we need to put it at github and strip it down to a very simple thing that is still buggy…

But in this case… I would suggest to start with the "clean" Yii code…

With that I mean the clean clientscript (without the unbind/undelegate/die)… and without the ehtml/fhtml…

As the idea is to solve this as it should be solved - a solution that will work in all situations…

Moreover… live() is deprecated… and all bind/delegate is advised to be changed to on()… but I would first like that we come here to a conclusion and than to make that change…

As i wrote many times… it all comes to the use cases and user code…

I created ajaxed pages with jQueryUI dialogs that holds activeforms with clientside and ajax validation working without any additional modification to the Yii core… so it is possible!