Endless loop when using jQuery to trigger an event on an object with a function with the same name

This name probably helps a little, but I tried. In any case, I ran into this extremely cryptic (and disappointing) error resulting in RangeError: Maximum call stack size exceeded in some OO JS that I wrote. Took me a couple of hours, but I finally got to it. Here is a simple example that will throw the same exception:

 // Class var Foo = function(){ // "Public" function this.bar = function(){ console.log('loop!'); $(this).trigger('bar'); } } var foo = new Foo(); $(foo).trigger('bar'); 

Running this code will cause loop! will be written to the console for a ton of times before ultimately leading to the exclusion of the range.

Obviously, something about the jQuery trigger function, which I donโ€™t understand, and it boils down to the following: why call the foo bar function at all? Yes, the event name and the function name of the class are the same, but I do not understand how the two are related.

+6
source share
4 answers

To fix this problem you will need .triggerHandler .

In jQuery docs :

Note. For ordinary objects and DOM objects other than a window, if the name of the triggered event matches the name of the property of the object, jQuery will try to call the property as a method if the event handler does not call event.preventDefault (). If this behavior is not desired, use .triggerHandler() instead.

http://jsfiddle.net/bcsqF/

+7
source

From the jQuery trigger documentation :

Description. Execute all handlers and behavior attached to the matched elements for this type of event.

bar is a Foo property or behavior, so the bar property (which is a method) is called on $(foo).trigger('bar'); . In bar , this function belongs to the Foo class, so $(this).trigger('bar'); . calls the bar function on foo. This would be a suitable call to this.bar () in the bar function, which is a more obvious recursion.

In general, this is not the behavior that I would expect, I expected that a trigger can only be called by DOM elements, but the documentation says otherwise.

+2
source

Allows you to search the jQuery source.

trigger :

 function (type, data) { return this.each(function () { jQuery.event.trigger(type, data, this); }); } 

jQuery.event

 function (src, props) { // Allow instantiation without the 'new' keyword if (! (this instanceof jQuery.Event)) { return new jQuery.Event(src, props); } ... // Put explicitly provided properties onto the event object if (props) { jQuery.extend(this, props); } ... } 

As you can see, the jQuery.event object jQuery.event designed in such a way that it is extended with your own properties. This means that you can use trigger to call them. Hence the cycle.

+2
source

In addition to invoking any connected event handlers, trigger will also attempt to invoke its own behavior. Therefore, if you call $('form').trigger('submit') in addition to executing any binding handlers, it will run its own form.submit method to actually submit the form. I assume that the trigger considers the object for the method with the same name as the triggered event, and assumes that it accompanies its own event that it raises.

+1
source

All Articles