CHtml::ajaxLink(), CHtml::ajaxSubmitButton() and similar methods are great, but if they are located inside a portion of the page that is already loaded via ajax something bad will happen, something you may even not notice if you are not using tools like firebugs: the sent ajax requests will multiply themselves.
Let's set up an example:
you have a page with a list of users. Every time you click on a username a div will be loaded via ajax, and this div will contain the user details plus another ajax link that will be used to display a floating div that will contain a form to send a message to the user.
The first time you load the user everything will be going just fine, and when you click on the "send a private message to the user" link just one request will be triggered.
If you load then another user (or the same user) when you click on the "send a message" link two request will be triggered, and then 3, and then 4 and so on.
The ajax request are triggered based on the link ID. Every time the div is reloaded through ajax a new delegate/event will be loaded pointing at the same ID of the one before him. So when you actually click on the link both delegates will do their job, because both match the clicked link.
The answer is extremely simple: assign to your ajax link a random ID.
You can achieve this result doing something like this:
CHtml::ajaxLink('send a message', '/message', array('replace' => '#message-div'), array('id' => 'send-link-'.uniqid()) );
Total 12 comments
In my case, I constantly update the content of a CJuiDialog through ajax.
Assigning a uniqueID is a quick fix, but not using the live handler (which binds the event to the document) seems to be the proper solution: ('htmlOptions' => array('live'=>false)).
ok, here is what I found out and how this post helped me:
when using CHtml::ajaxSubmitButton or CHtml::AjaxLink 1 all the time CHtml::ajaxSubmitButton and CHtml::AjaxLink should be used with 'live'=>false and should have an unique id:
2 if it is a normal request then it should look like this:
3 if it is an AJAX request, then if should look like:
All this result in the following controller action code:
In this way all the time when it's an AJAX request, the javaScript code is rebind to the element.
hope that this helps someone...
http://www.yiiframework.com/forum/index.php/topic/35912-chtmlajaxlink-with-yiiapp-request-geturl/page__st__20
http://www.yiiframework.com/forum/index.php/topic/35912-chtmlajaxlink-with-yiiapp-request-geturl/page__st__20
please look at the problem
the forum post http://www.yiiframework.com/forum/index.php/topic/35912-chtmlajaxlink-with-yiiapp-request-geturl/page__p__172871#entry172871
http://www.yiiframework.com/forum/index.php/topic/35912-chtmlajaxlink-with-yiiapp-request-geturl/page__p__172871#entry172871
this is related to this topic
the first 3 links are active only after some submit. after that when we click on that "name" link the link "A" with previous values are working..
like that when we click on that "add.No" link the link "B" with previous values are working..
when we click on that "Batch" link the link "C" with previous values are working..
this is the problem. the link shown is correct but working is previous one.
I have been given the run around by this problem for 2 days... I had multiple forms being renderPartial'd over and over via ajax calls.
I have found the following neat Yii based solution which seems to work for me - as ever you mileage may vary.
So you have a _form being rendered from a view:
In the _form partial view you have and ajaxlink/submit button etc
The key to not have the element be bound multiple times to the js is to put "live"=>false as one of the HTML options: from: http://www.yiiframework.com/doc/api/1.1/CHtml#clientChange-detail
live: boolean, whether the event handler should be attached with live/delegate or direct style. If not set, liveEvents will be used. This option has been available since version 1.1.6.
direct style seems to attach to this element and this element only, and once. Add this to all your ajaxLink ajaxSubmitButtons etc and the problem may go away for you
HTH someone.. nearly killed me !
to avoid ajax request on CHtml, just use CHtml::$liveEvents=false; or CHtml::ajaxLink('label','url',array(),array('live'=>false)); i usually place this on beforeAction($action) controller method; on controller:
public function beforeAction($action){
if(Yii::app()->request->isAjaxRequest) CHtml::$liveEvents=false; parent::beforeAction($action); }
edited: not work on CHtml::ajaxLink method but with CHtml::$liveEvents=false; you can use Yii::app()->clientScript->('unbindAjax','$("#ajaxLinkId").unbind("click")'); for every ajax request that have CHtml::ajaxLink to avoid multiple ajax request.
thanks for starting this post.
This is what worked for me:
In the htmlOptions array of your ajaxLink, give the link an id of uniqid()
Then possibly in your controller you'll need to disable unnecessary loading of .js files. Check the net tab in firebug to make sure your app is not requesting the same .js files everytime you do an ajax post...
Yii::app()->clientScript->scriptMap['*.js'] = false;
In my opinion, the problem is the clientChange function of CHtml. Why to register a script and not output the ajax stuff directly if used in a ajax area?
I have detected this article after the release of the extension ajaxutil
It should be easy to add a option 'directOut' to the ajaxOptions of CHtml::ajaxXX elements in the Yii core - see me feature request ajax-handling
Besides: The extension handles the problems with pagers, when loaded inside an ajax area too.
of course the easy solution is a workaround :P the main point of the article is making you aware of what causing the problem...
the best thing would be of course not to load any additional js binding the same link more then once
I think this is an easy solution, but this is only workaround which hides the real problem, isn't it? The real cause of multiple ajax requests is that ajaxLink() uses 'live' to bind an event by default. So when you render a part of HTML along with javascript code then you have multiple handlers binded to the same HTML element. So usually you can whether: - configure ajaxLink to use bind instead of live (pass 'live'=false to the ajaxOptions array) - do not render scripts when returning HTML on the server side – in the controlled do $renderPartial->('view', $data) instead of $renderPartial('view', $data, false, true)
Maybe you have some other case, but I faced this problem many times and it definitely can be solved without such workaround. But also I think you described a really easy solution which can be acceptable in some cases.
rand was just an example of a possible solution, you can use more accurate functions to generate the random string like time(), uniqid() or microtime()
RAND_MAX on some systems could be as low as around 32,000 meaning that eventually if the site is used enough rand() should statistically return the same value for 2 versions of the content div. If the site is dependent on only having one AJAX request generated then this will fail in a way that is almost impossible to replicate. If this is considered the best technique then perhaps an incrementing counter could be used, or better still, use jQuery when processing the AJAX request to cancel the all event listeners for the link.
Leave a comment
Please login to leave your comment.