Open GoogleCodeExporter opened 9 years ago
Thanks.
Original comment by qiang.xue
on 7 Dec 2008 at 1:11
Issues are also found in widget classes. We need a better solution.
The cause of this issue is that js in "ready" function is called before the ajax
"update/replace" is performed. Therefore, the expected onclick and other event
handlers are not hooked to the corresponding HTML elements generated by ajax
"update/replace".
A possible solution to this problem is that we wrap those js inside a function
and
register this function to "ready". For ajax "update/replace", we explicitly
call this
function. A potential problem is that an onclick handler might be registered
multiple
times.
Original comment by qiang.xue
on 9 Dec 2008 at 1:57
This is good idea. Registering multiple times is not a problem. There can be
global
variable which can store in array of boolean whether the function was
registered.
Original comment by rb.pa...@gmail.com
on 9 Dec 2008 at 4:13
Please look here:
http://www.yiiframework.com/forum/index.php/topic,249.msg1527.html#msg1527
Original comment by rb.pa...@gmail.com
on 22 Dec 2008 at 6:51
This might be caused by a jquery issue
http://groups.google.com/group/jquery-dev/browse_thread/thread/9f8d25fc9f43b859?
hl=en
Original comment by qiang.xue
on 25 Dec 2008 at 1:18
This issue needs further investigation. Move to 1.0.2.
Original comment by qiang.xue
on 3 Jan 2009 at 8:31
This may also relate to this thread
http://www.yiiframework.com/forum/index.php?topic=90.0
Basically this is an ajax button updating a section with another ajax control.
The second control is sent with the related javascript to wire the control
(using
jquery). But is not activated because it is wrapped within a
"jQuery(document).ready(" function which never gets called.
Original comment by notzi...@gmail.com
on 6 Jan 2009 at 4:59
Not entirely true. Yes, we should not put js code in ready() when they are
returned
in ajax response. But still, this issue is not solved. The underlying problem
is that
when the ajax response comes, there are two elements with the same ID: one in
the
original page, and one in the ajax response. The original element is replaced
by the
latter. It gets tricky how the replacement is done because it affects how the
events
are bound.
Original comment by qiang.xue
on 6 Jan 2009 at 5:01
You could collect all the events bound to the element by using a
jQuery.data(elem,
"events"), and then rebind them afterward. This would ensure all originally
bound
events to the control were rebound. This would work fine if nothing was changed
in
the way the control operated. But if the event handlers were required to be
changed
then you would need to unbind and bind the new event handler manually which
could be
tricky since you do not know which group of events are being changed.
Just some thoughts..
Original comment by notzi...@gmail.com
on 22 Jan 2009 at 6:40
Need more time on this issue. Moved to 1.0.3.
Original comment by qiang.xue
on 30 Jan 2009 at 8:34
Original comment by qiang.xue
on 1 Mar 2009 at 3:48
Original comment by qiang.xue
on 5 Apr 2009 at 8:51
I was having problems with this
found out about about the 'live' feature of Jquery
http://docs.jquery.com/Events/live
would that be a solution ?
does not work for all events though
any progress on a yii solition ?
thanks
Original comment by thomas.mery@gmail.com
on 6 Apr 2009 at 11:10
I've found in jQuery group following discussion, which may help us to solve this
problem:
http://groups.google.com/group/jquery-en/browse_thread/thread/7c21eb3722361e58/b
a5475801d1c4a1b?lnk=gst&q=ajax+works+once#ba5475801d1c4a1b.
I've found also that lambda function may help instead wrapping ready function:
http://www.learningjquery.com/2006/09/sacrificial-lambda.
There are also some plugins which are helpful when working with dynamic content:
- http://plugins.jquery.com/project/Listen
- http://plugins.jquery.com/project/Intercept
- http://plugins.jquery.com/project/livequery
Maybe we (yii'ers) should decide to use one of them?
Original comment by tomasz.s...@gmail.com
on 23 Apr 2009 at 9:08
Need more time.
Original comment by qiang.xue
on 28 Apr 2009 at 1:09
Is there a way to solve this? It's quite annoying, I can't get my ajaxLink
working
inside an ajax request...
Original comment by andy.dam...@gmail.com
on 4 Aug 2009 at 12:51
Original comment by qiang.xue
on 10 Sep 2009 at 7:52
I worked with Symfony and similar functionality works fine. They are using
Prototype
instead.
Maybe someone good with js (I am far from that) could take a look o their code.
Original comment by luciano....@gmail.com
on 30 Oct 2009 at 10:44
It`s almost a year now. What`s the status?
Original comment by mirko.ee...@gmail.com
on 20 Nov 2009 at 4:11
[deleted comment]
[deleted comment]
[deleted comment]
I've try to fix this, here is my solution for this issue:
in the method CHtml::clientChange I've replaced code:
$cs->registerScript('Yii.CHtml.#'.$id,"jQuery('#$id').$event(function(){{$handler}});");
with this one
// check for currently not supported events by jQuery v1.3 `live`
if(preg_match('/^(blur|focus|mouseenter|mouseleave|change|submit)$/si', $event))
$cs->registerScript('Yii.CHtml.#'.$id,"jQuery('#$id').$event(function(){{$handler}});");
else
$cs->registerScript('Yii.CHtml.#'.$id,"jQuery('#$id').live('$event',function(){{$handler}});");
checked in FF 3.5, IE 8, Opera 10, it works, so I think, this can be used as
temporary solution
Original comment by a.jil...@gmail.com
on 30 Nov 2009 at 6:40
From what I've found the problem is most likely with jQuery. What seems to
happen is
when you include the main jQuery file in say an ajax call it will reset the
jQuery
environment.
As i've noticed with trying to use ajaxLink you've already changed it so that
the
links are embedded in a script tag if process output is set true, however you
reinclude the jquery file which in my case wipes out my jquery ui objects, so
while
clicking the link fetches the html i expect my javascript ui window doesn't
come up.
CClientScript's behavior for ajax calls might be better served if it didn't
serve the
registered script files unless they were specifically asked for say you were
sending
an ajax call with html to insert and need a javascript file that specifies the
behavior of what your sending.
Proposed changes:
1. On ajax requests CClientScript should not send out script files and move all
registered scripts to the body. The reasoning here is that if your doing ajax
calls
you probably have already everything setup as far as jQuery etc and the script
tag
will get evaluated in html calls.
2. have a function to tell CClientScript that we do what to include a file such
as
registerAjaxScriptFile. The reasoning here is your web app may be designed so
that
certian features of it are loaded via ajax and you don't need the javascript
that
makes the feature work till then.
3. For non ajax calls allow us to tell CClientScript it should go into ajax
mode, the
reason here is that you may be faking an XmlHttpRequest with a get or post due
to
cross site request limitations like i do when i submit user information from
http ->
https via a jsonp call.
another simpler means might just be to add a function to CClientScript to
unregister
a file. I believe at least for registering script chunks you could unregister
it by
passing null or an empty string to the register function.
Original comment by dorml...@gmail.com
on 30 Nov 2009 at 6:43
My apologies I'm using 1.0.10 though it seems that this may be a problem with
1.1 as
well.
Original comment by dorml...@gmail.com
on 30 Nov 2009 at 6:48
additional for my comment #23
IDs collision possible, if ID autogenerated by Yii
example:
- view contains 2 links (IDs: yt0, yt1), but ajax returns only 1 ajax link (ID:
yt0)
in response, so returned link will use events of yt0
my solution solves only a half of the problems (rebinding of the events) :(
Original comment by a.jil...@gmail.com
on 30 Nov 2009 at 7:02
also for Ajax links in the Ajax response we nee ability in CClientScript to
flush/return generated handlers instead of put them into HTML (in $content)
Original comment by a.jil...@gmail.com
on 30 Nov 2009 at 7:19
dormlock: The method to block the sending of script files has been in Yii for a
while. It is invoked like Yii::app()->clientScript->scriptMap['*.js'] = false;
This
will block any javascript file being included in the response.
Original comment by notzi...@gmail.com
on 30 Nov 2009 at 2:10
Thanks notzippy. I knew about the scriptMap as i use it to map my javascript
files
differently depending on whether the app is running in development mode vs
production.
I just looked at the guide and api and see i missed this fact.
a.jilkin you can get around the id collision by passing the id in through the
html
options something like: array('id'=>'myid') this would prevent the name
collisions,
however since the block of code is evaluated it will rebind any of the ids with
the
same name, ie both of the yt0's would use the new code not the old code.
I also don't see a reason why you would need to get the generated handlers and
not
let them be included with the rendered view. The only reason i could see
wanting to
is if you wanted to send the data back in a formatted data response like json.
Original comment by dorml...@gmail.com
on 30 Nov 2009 at 3:21
dormlock: yes, ID can be specified in the htmlOptions, I've only describe
possible
problem if ID will be generated by Yii.
Reason to add ability to get all generated handlers is for flexibility of
CClientScript.
Original comment by a.jil...@gmail.com
on 1 Dec 2009 at 10:31
it seems, my patch (see comment #23) completely solves this problem,
here is a test example:
1. generate webapp
2. add action Update to the default controller
public function actionUpdate()
{
$this->layout = false;
Yii::app()->clientScript->scriptMap['*.js'] = false; // thanks, notzippy ;)
$this->render('update');
}
3. add alaxLink to the default view
<div id="firstDiv">
<?php echo CHtml::ajaxLink('My Link',
array('/default/update'),
array('replace' => '#firstDiv'),
array('id' => 'updateFirstDiv')); ?>
</div>
4. add view for Ajax response
<div id="firstDiv">
<?php echo CHtml::ajaxLink('New Link',
array('/default/update'),
array('update' => '#secondDiv'),
array('id' => 'updateSecondDiv'));
?>
</div>
<div id="secondDiv"></div>
5. open webapp URL
6. click "My Link" --> #firstDiv replaced with new ajaxLink
7. click "New Link" -> second DIV successfully updated by ajaxLink from response
Original comment by a.jil...@gmail.com
on 3 Dec 2009 at 4:52
Original comment by qiang.xue
on 9 Jan 2010 at 9:05
When you call CController::renderPartial($view, $data, false, true), a <script>
with
the appropriate event handler is sent. The problem is that jQuery evaluates the
<script> *before* the DOM is updated, which means it adds the event listener to
an
element that immediately gets removed from the page, instead of the new one
that is
replacing it.
The solution to this is simply to wrap the jQuery.bind call in an anonymous
setTimeout function, so that its execution is delayed until after the DOM has
been
updated, like so:
--- yii-1.1.0.r1700/framework/web/helpers/CHtml.orig.php 2010-02-11
02:45:46.000000000 -0600
+++ yii-1.1.0.r1700/framework/web/helpers/CHtml.php 2010-02-11
02:40:44.000000000 -0600
@@ -1779,7 +1779,7 @@
$handler="return $confirm;";
}
-
$cs->registerScript('Yii.CHtml.#'.$id,"jQuery('#$id').$event(function(){{$handle
r}});");
+
$cs->registerScript('Yii.CHtml.#'.$id,"setTimeout(function(){jQuery('#$id').$eve
nt(function(){{$handler}});},
1);");
unset($htmlOptions['params'],$htmlOptions['submit'],$htmlOptions['ajax'],$htmlOp
tions['confirm'],$htmlOptions['return'],$htmlOptions['csrf']);
}
This is tested and works properly in IE7, Firefox 3.5, Safari 4, Chrome 4, and
Opera
10.10. There should be very low risk of breaking compatibility unless somebody
has
already tried to manually work around this issue in their code.
One final point to note is that if you rely on Yii to generate unique IDs for
you,
the ID generated in the partial might end up matching one that was already
created
and used on part of the page that *isn’t* getting replaced. It would probably
be wise
if Yii switched to using uniqid() or similar when generating IDs to ensure that
they
are truly unique, even across AJAX loads.
Regards,
Original comment by goo...@zetafleet.com
on 11 Feb 2010 at 8:51
About the generated ID's: I can't agree more, see
http://code.google.com/p/yii/issues/detail?id=762
Original comment by maxximus...@gmail.com
on 11 Feb 2010 at 9:49
[deleted comment]
This issue was closed by revision r1818.
Original comment by qiang.xue
on 18 Feb 2010 at 10:45
Thank you all for participating in the discussion.
I am closing this issue by using the 'live' event handling approach.
Original comment by qiang.xue
on 18 Feb 2010 at 10:46
live() does not solve this issue.
First, if you are using renderPartial() with $processOutput = true (which would
be
normal and correct behaviour for a partial rendering that is being returned as
the
complete content, according to docs) and that partial contains a CHtml AJAX
element,
you end up binding another anonymous function without removing the old one every
single time the section containing the AJAX element is reloaded.
Second, if you replace a section of the page with new content that contains an
element with the same ID but which performs a different action (say, a
dynamically
loaded multi-part form), the live() approach *does not* solve the problem. The
old
event handling function will continue to exist even after the object that it
initially was bound to is gone, leading to incorrect behaviour.
Also, this prevents garbage collection from removing unused anonymous functions,
which means memory leaks for long-running Yii RIAs.
The correct solution is to ensure the DOM is updated before attempting to
attach the
event listener. Adding live() support is good for other reasons, but it is not
the
solution.
Regards,
Original comment by goo...@zetafleet.com
on 18 Feb 2010 at 11:09
Perhaps the new delegate() and undelegate() functions in 1.4.2 will help
keeping the
DOM sane, instead of using live().
I still like to see a better way how id's are generated by default, the current
method
is not suitable for today's environments. Using uniqid() is probably not the
solution
when using delegate(), since undelegate() will be difficult. Perhaps generating
an
unique ID based on the supplied attributes could be done.
Original comment by maxximus...@gmail.com
on 21 Feb 2010 at 12:46
@Comment #39: There is *no* .live() method that can be used that will properly
fix
this problem, as per my previous comment. These events should *not* apply to all
future elements that match the selector. All .delegate() does is improve
performance
by binding the events to a context. .live() is *not* a suitable replacement for
event
bindings that may change based on the data that loads. One should not have to
remember to .die() an event binding when using setTimeout to delay binding until
after the DOM is updated fixes the problem.
Original comment by goo...@zetafleet.com
on 21 Feb 2010 at 7:39
This one is not fixed. Checked with r2336.
Original comment by alexander.makarow
on 25 Aug 2010 at 10:01
I continue to manually apply the attached patch to resolve this issue, which is
the same fix mentioned in Comment #33.
Original comment by goo...@zetafleet.com
on 25 Aug 2010 at 5:47
Attachments:
With the new 'delegate' usage, this issue should already be fixed.
Original comment by qiang.xue
on 31 Aug 2010 at 3:08
Hi Qiang,
Could you please explain how delegate does anything to resolve the issues that
I raised in Comment #38? Seeing as how the only difference between live and
delegate is that live binds to the document, whereas delegate binds to an
element lower in the DOM, I don’t see how it addresses this problem.
Original comment by goo...@zetafleet.com
on 31 Aug 2010 at 5:34
Both issues you reported are certainly valid, but I doubt there is a simple
solution to them. For example, assume in the initial request, you use some
jquery plugin. And then in ajax response, you include once again jquery.js. You
may find the jquery plugin stops working because of the re-inclusion of jquery.
I think it is more a responsibility of the developer to properly write the js
code to do any necessary cleanup. I don't think the timer solution alone can
fully solve this issue.
In fact, in real practice when dealing with very complex ajax interactions, we
usually use the approach that we first include all necessary js files, and then
in ajax responses, we only pass back json data, and on the client side we
analyze the json response to perform any necessary js actions.
Original comment by qiang.xue
on 31 Aug 2010 at 5:50
Issue 1138 has been merged into this issue.
Original comment by qiang.xue
on 1 Sep 2010 at 2:39
Issue 1315 has been merged into this issue.
Original comment by qiang.xue
on 2 Sep 2010 at 2:24
@Comment 45
You’re absolutely correct on all accounts. I don’t think there will ever be
a 100% perfect solution to this problem, but I do think we can do better. The
provided patch works well for my situation, which I imagine is a pretty common
case (a simple pre-CActiveForm AJAX form that loads over itself), but you’re
right that it doesn’t solve every potential issue, and the reloading of
jquery.js is quite icky. So, I would suggest the patch from Comment 42 also
requires a change to CController::processOutput.
During an AJAX request, it is safe to assume that jquery.js is already loaded
(since otherwise AJAX would not work), so we can suppress loading that file. We
would also need to avoid loading any scripts that were mapped to jquery.js.
Other than that, reloading scripts (such as plugins) should be safe. I can work
on a patch for this if you would like.
I do just want to mention that once you get to the point where you are
preloading code to manage your AJAX calls, you’re probably not going to be
using CHtml’s AJAX stuff anyway. In my experience, it’s really mostly a
convenience to load simple page fragments, and its utility is greatly
diminished when those fragments can’t include widgets.
Regards,
Original comment by goo...@zetafleet.com
on 2 Sep 2010 at 3:07
Through my past experience of client side scripting (a lot of ajax involved), I
think it's better for us to stop here without doing anything further.
Reloading non-jquery scripts may not be safe either because the property
initialized previously may be overwritten and thrown away.
As you and I both agree, the proper solution to this issue is preloading client
side code that are needed in later ajax responses. So instead of thinking of
ways to patch for this issue, why not leave it there and let developers to
realize it so that they can go on the right track earlier?
Original comment by qiang.xue
on 2 Sep 2010 at 3:55
Hi,
You could add a CClientScript position POS_REHOOK
all scripts registered there may be wrapped in a rehook() JS function
an CHTML::ajaxRehookLink custom function would fire rehook('#html_id') on ajax
complete, therefore rebinding any events to newly created elements
Original comment by tudorili...@gmail.com
on 23 Mar 2011 at 4:18
Original issue reported on code.google.com by
rb.pa...@gmail.com
on 4 Dec 2008 at 4:01