I want to debounce a keyup event on a table of rows which causes an AJAX call. I have used all debouncing plugins out there, including the one for jQuery by Ben Alman, the one from Underscore.js, the jQuery delayed() plugin, as well as one plugin from Filatov Dmitry which extends jQuery (like Ben Alman's).
My code looks like this:
function onKeyUp(evt) {
doSomethingWith(evt, true);
}
$('#mytable').on('keyup', $.debounce(500, onKeyUp));
The problem is that, while it works fine on Firefox and IE9, it doesn't work in IE8. Specifically, IE8 throws a "Member not found" error when I call evt.preventDefault() which goes into the jQuery 1.11.1 code and breaks in line 4967 on e.returnValue = false; (because preventDefault() apparently doesn't exist in IE8). Upon inspection of the event variable with the IE developer tools debugger, it seems that the variable contains all event member methods and properties, but most of them are marked as "Member not found".
I've alread tried this solution https://stackoverflow.com/a/3533725/134120 but it did not work.
Googling for "IE member not found" returns a lot of results, but not many solutions.
So, any ideas?
I need to first prevent the default handler (i.e. no scrolling) and then debounce my event handler.
Then use this:
var onKeyUp = $.debounce(500, doSomethingWith);
$('#mytable').on('keyup', function(evt) {
evt.preventDefault(); // do always
onKeyUp(evt, true); // possibly bounced call to doSomethingWith
});
Related
Can I check if a onresize method was set?
I've previously used:
$(window).resize(function() { /* ... */ });
Due a unknown bug in another library, onresize is not called anymore. After executing above line it works perfectly again. The method is invoked once. If I execute the line in the Firebug console again, the method is invoked twice.
I would like to write a workaround, which sets onresize as soon as it's "reseted".
I'm looking for something like that: (undefined or null)
if (window.onresize == undefined) { /* ... */ }
The external library/framework is Richfaces 4 (Extended Data Table). As soon as I sort a column, some of the onresize function handler were gone.
Before:
$._data(window,'events').resize
// result on the Chrome console:
[Object, Object, Object, Object]
After using sorting:
$._data(window,'events').resize
// result on the Chrome console:
[Object]
I'm looking for a way to write a workaround.
JIRA Issue
https://issues.jboss.org/browse/RF-13117 (fixed with future release 4.3.4)
You could use $._data() which is not a method publicly supported:
$(window).on('load',function() {
if(!$._data(window,'events').resize)
alert('none resize bound');
});
In older jquery version it was: $.data()
what i used in my project was
$(window).unbind('resize').bind('resize',function(){
//code here
});
it will remove all the previously bind (registered) handlers for resize event and register this new function as the handler.
this approach is useful only when you want to attach a single event handler.
Thanks for all answers and comments. As suggested I went to the source of the problem and wrote for that a workaround including opening an issue.
window.RichFaces.ui.ExtendedDataTable.prototype.deActivateResizeListener = function() {
if (this.resizeEventName != undefined) {
$(window).off(this.resizeEventName);
}
};
I accepted roasted answer since it really helped to find a workaround and his answer answered my question if there is a way to find out if a event handler is attached.
I have a fairly simple ASP.NET page that renders an HTML input (text box). Within the generated HTML, I attach a handler to several events, including onfocus, onkeypress, and onkeyup. Because this is a solution targeted at a version of IE that does not support addEventListener (situation about which I can do nothing), I am forced to use attachEvent.
A typical call to attachEvent is as follows - I've excerpted this source from the original for the sake of brevity/clarity, so it is not precisely the code at issue:
var hostControl = document.getElementById('mytextbox');
var attachResult = hostControl.attachEvent('onfocus', function(){
hostControl.select();
});
if (!attachResult)
{
alert('Attach failed.');
}
attachResult = hostControl.attachEvent('onblur', function(){
if (hostControl.value=='')
{
alert('Warning - no entry.');
}
});
if (!attachResult)
{
alert('Attach failed.');
}
When I step through this code in the IE debugger, attachEvent returns 'true' in both instances, which should indicate that the event attachment attempt was successful. However, when I look at the [Event] handlers for the control within the debugger, all the events show 'null', no handler attached.
Things I've tried/researched:
I've read several different articles on the vagaries of event attachment in IE, so I've speciously avoided any 'this' references.
I tried one version that used one of the addEvent wrapper blocks that tries to use addEventListener if available, even though I knew this would be an IE solution.
When I tried that version against FireFox, event attachment worked properly through addEventListener, but failed in IE using attachEvent (with attachEvent still returning true).
I then opted to eliminate any possible problems the wrapper might be introducing, and used attachEvent directly against the control, which leads me where I am now. The problem persists.
I would like to think I've simply overlooked something very simple, as I've hooked up events before without difficulty, but something here is throwing me a curveball I just don't recognize. Appreciate the extra eyeballs on this to see where I've erred.
I'm working on a project where a number of different companies are working on the same site.
The main developer have set up an event - let's call it init - which indicates the page is ready for our code to execute.
They're basically calling it like this:
$(window).trigger('init');
For a number of reasons I won't go into here, we prefer to avoid using jQuery in our own code wherever possible. I tried to bind to it like this:
window.addEventListener('init', function (event) {
alert('hehehehe');
});
But that doesn't seem to work. This works perfectly, though:
$(window).bind('init', function (event) {
alert('hehehehe');
});
Does jQuery use special event objects by default that you can't bind to with plain JS? Am I just doing something stupid?
The docs for bind seem to contain the answer:
Any string is legal for eventType; if the string is not the name of a native DOM event, then the handler is bound to a custom event. These events are never called by the browser, but may be triggered manually from other JavaScript code using .trigger() or .triggerHandler().
There's no native DOM event called 'init':
http://en.wikipedia.org/wiki/DOM_events
Hence "These events are never called by the browser, but may be triggered manually from other JavaScript code using .trigger() or .triggerHandler()"
I have a class that extends dijit.Dialog but only to set default functionality and buttons for my site. When clicking the dialog's cancel button the following code is run:
this.actionDialog.destroyRecursive();
this.actionDialog.destroy();
nb this.actionDialog = dijit.Dialog
Sometimes (not always) the following error gets thrown:
Uncaught TypeError: Cannot call method 'destroy' of undefined
DialogUnderlay.xd.js:8
Which causes following dialogs to incorrectly display. I am using 1.5 from Google API's. Am I missing something with the underlay code?
Error thrown after Ken's answer:
exception in animation handler for: onEnd
TypeError: Cannot read property 'style' of null
Both from dojo.xd.js:14. But the code still works properly.
I'm still not entirely sure what the problem is, other than for some reason dijit.DialogUnderlay code is getting confused. FWIW, this doesn't happen in Dojo 1.6.
While I was poking at some potential solutions, I seemed to accidentally find out that avoiding this problem is perhaps as easy as calling hide() on the dialog immediately before destroying it, e.g.:
this.actionDialog.hide();
this.actionDialog.destroyRecursive();
Alternatively, you might be interested in hiding the dialog, then destroying it once the hide animation finishes.
Here's how you can do it on Dojo 1.5 and earlier (tested 1.3+):
dlg.connect(dlg._fadeOut, 'onEnd', function() {
this.destroyRecursive();
});
dlg.hide();
In 1.6, the fadeOut animation is no longer exposed on the instance (granted, it was technically private earlier anyway), but onHide now triggers once the animation ends (whereas before it triggered as soon as it began). Unfortunately a setTimeout is needed to get around an error that occurs due to other code in the branch calling onHide, which assumes that something still exists on the instance which won't after we've destroyed it (see #12436).
dlg.connect(dlg, 'onHide', function() {
setTimeout(function() { dlg.destroyRecursive(); }, 0);
});
dlg.hide();
See it in action on JSFiddle: http://jsfiddle.net/3MNRu/1/ (See the initial version for the original error in the question)
The dialog.hide() method returns a Deferred, your code can be something more readable like this:
var dialog = this.actionDialog;
dialog.hide().then(function(){ dialog.destroyRecursive(); });
Be careful not to do this:
this.actionDialog.hide().then(function(){ this.actionDialog.destroyRecursive(); });
At the context of then this has another meaning!
You only need to call destroyRecursive()
The second destroy command is what is probably causing the error, and the error probably is causing the issues with other dialogs.
http://dojotoolkit.org/api/1.3/dijit/_Widget/destroyRecursive
destroyRecursive
Destroy this widget and it's descendants. This is the generic "destructor" function that all widget users should call to cleanly discard with a widget. Once a widget is destroyed, it's removed from the manager object.
I was getting the IE8 error : 'this.focusNode.form' is null or not an object. I found this was the result of the dialog.hide() returning a deferred. I wrote my own _closeDialog which eliminated the IE error.
_closeDialog : function(cntxt){
cntxt.popup.hide().then(
function(){
cntxt.popup.destroyRecursive(false);
cntxt.popup.destroy(false);
cntxt.destroyRecursive(false);
cntxt.destroy(false);
});
},
I am using js-hotkeys. I have a problem where when my key combination is more than 1 key, eg. "Shift+Tab", my function is raised twice.
$("textarea").bind("keydown", "shift+tab", function() { ... });
See what happens here -> http://jsbin.com/osuza5/2/edit. seems like with 1 key it also triggers twice there.
This has happened since jQuery 1.4.2, it's a known issue. Luckily, John Resig forked this and created a much cleaner version a while back that also ...well - it works, you can check it out here.
Updating your jsbin to point at this plugin version: https://github.com/jeresig/jquery.hotkeys/raw/master/jquery.hotkeys.js (and that's the only change), it works. You can test it out here.
Try Code:
$("textarea").bind("keydown", "shift+tab", function(e)
{ e.preventDefault; bla..bla... });
Link: http://jsbin.com/osuza5/4/edit
Notice the combinations mentioned twice during binding. One along with the "keydown.shift+tab".
To keep it from firing multiple times in some browsers, unbind the hotkey in the end of the function. This worked for me.
I've used the original version from http://code.google.com/p/js-hotkeys/
Please note that using this will probably keep you from overriding any of the browser defaults. Hence, even though things will go as expected, but as soon as the unbinding occurs, the browser may switch tabs (shift+tab) because of this .
$("textarea").bind("keydown.shift+tab", "shift+tab", function() { ...
//Your Code Here
//this should be in the end
$("textarea").unbind("keydown.shift+tab", "shift+tab");
});