views:

315

answers:

4

I write the following code all the time to handle when the enter key pressed:

    $("#selectorid").keypress(function (e) {
        if (e.keyCode == 13) {
            var targetType = e.originalTarget ? e.originalTarget.type.toLowerCase() : e.srcElement.tagName.toLowerCase();
            if (targetType != "textarea") {
                e.preventDefault();
                e.stopPropagation();
                // code to handler enter key pressed
            }
        }
    });

Is there a way to extend jQuery so that I could just write:

$("#selectorid").enterKeyPress(fn);
+1  A: 

You can extend jquery something like:

jQuery.fn.returnPress = function(x) {
  return this.each(function() {
    jQuery(this).keypress(function(e) {
      if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
        x();
        return false;
      }
      else {
        return true;
      }
    });
  });
};

Which can be invoked like:

$('selector').returnPress(function() { alert('enter pressed'); });
David G
Relevant docs: http://docs.jquery.com/Plugins/Authoring
insin
+1  A: 

You can define it as a plugin with a bit less code like this:

jQuery.fn.enterKeyPress = function(callback) {
  return this.not("textarea").keypress(function (e) {
    if (e.keyCode == 13) {
      callback($(this));
      return false;
    }
  });
};

Use like this:

$("input").enterKeyPress(function() { alert('hi'); });

This approach still ignores <textarea>, but instead of checking every keystroke, we just never bind the keypress event to any textarea.

Nick Craver
this.not("textarea") will not work because 'this' will be the form. not the input. The rest works :)
Kenneth J
@Ken - Judging by your answer, it seemed like you'd be binding this to a textbox or other input. You could bind this format with delegate however, and it'd capture all keypress events not in a textbox like your question, e.g. `$("#formId :input")` as the selector.
Nick Craver
Events bubble up. The original target would be the input but the event will be handled at a container div (or form.) Sorry the ambiguity I should have made the question clearer. Thanks for the answer.
Kenneth J
Nice answer, is it then possible to enable `bind("click","enterKeyPress"` then?
Dr. Frankenstein
Not in this case, well you can but it wouldn't do anything because it's not firing that event. You could create a `.live()` handler for all elements that did `$('textarea').keypress(function(e) { if (e.keyCode == 13) { $(e.target).trigger('enterKeyPres'); } });` if you wanted it as an event, with that in place then you could bind it, `.bind('enterKeyPress', myfunction);` :).
Nick Craver
+1  A: 

You can do what David G says, but perhaps the most correct way to approach this would be to write a custom event:

$(document).keypress(function(evt){
    if(evt.keyCode==13) $(evt.target).trigger('enterPress');
});

Which could be bound like so:

$(document).bind('enterPress', fn);

See an example here: http://jquery.nodnod.net/cases/1821/run

The advantage to this approach is that you can bind, unbind, namespace, and trigger the event like any other event in jQuery.

cpharmston
Of course, evt.target doesn't work in IE. Use evt.srcElement in those cases.
cpharmston
@cpharmston: the code is using jQuery. `.target` works in jQuery.
Crescent Fresh
+1 for being the only solution (so far) which actually uses a custom event. ;-)
Ben Blank
A: 

This is what I use to capture the enter key on any form element, and convert it into a tab. I have made it so the enter key works normally in a textarea, and on submit, reset and button elements.

$.fn.focusNext = function(e) {
  var t = $(this);
  if ( t.is(":submit")==true || t.is(":reset")==true || t.is("textarea")==true || t.is("button")==true ) { exit(); }

  if (e.which==13 || e.which==3) {
    return this.each(function() {
      e.preventDefault();
      var fields = $(this).parents("form:eq(0)").find(":input:visible");
      var index = fields.index( this );
      if ( index > -1 && ( index + 1 ) < fields.length ) { fields.eq( index + 1 ).focus(); }
    });
  }
  return true;
};

And to use it, it's called like so

$(":input").keypress(function(e) { $(this).focusNext(e); });

OR

$(":input").live("keypress", function(e) { $(this).focusNext(e); });
Jason Gradwell