16

Is there a library that can extract all text events from an <input type=text> (or contentEditable -- any one-line input field) element?

In particular, I need to know whenever the text is changed by:

  • typing (asdf, backspace)
  • cut/paste
  • key combo actions (e.g. ctrl+bksp or option+bksp deletes the previous word)
  • dragged & dropped text
  • edit menu actions

And preferably what it was that changed (whether and what text was inserted, deleted, or replaced).

Needs to work on Chrome, Safari, Firefox 3+, IE9+.

nornagon
  • 15,393
  • 18
  • 71
  • 85
  • Were you able to achieve what you were looking for? What did you use finally? – eozzy Dec 19 '14 at 14:57
  • I used the `oninput` event as described in the accepted answer. There's no way to find the changed text, but you can see how sharejs does it: https://github.com/share/ShareJS/blob/master/lib/client/textarea.js – nornagon Dec 20 '14 at 22:18

3 Answers3

26

The HTML5 oninput event is supported by all those browsers and works very much like the onchange event, but fires as soon as the element's input changes. It also bubbles, so you can capture it further up the document tree.

element.oninput = function () {

}

Working demo: http://jsfiddle.net/Zfthe/

http://whattheheadsaid.com/2010/09/effectively-detecting-user-input-in-javascript

Andy E
  • 338,112
  • 86
  • 474
  • 445
  • 1
    I knew what I'd find when I saw this question in the list, and sure enough, there was your answer :) – Tim Down May 19 '11 at 10:35
  • @Tim: Ha! I feel like I'm beginning to sound like a broken record :-) At least this question wasn't riddled with answers saying *"use onkeyup!"*... – Andy E May 19 '11 at 10:36
  • @nornagon: can't be done in a straightforward/easy manner. The event doesn't expose anything like that in a property so you'd have to store the previous value in a variable and update that variable every time the text changes, comparing the two values. – Andy E May 19 '11 at 10:44
  • I don't want to write a diff algorithm just to work out what happened :( I'm using this to interface with a Wave-like operational transform library, so the deltas are important. Would it be easier with a contentEditable element? – nornagon May 19 '11 at 10:45
  • @nornagon: nope, afraid not. If anything, it would be more difficult because you're diffing HTML rather than text. – Andy E May 19 '11 at 10:48
  • 1
    @nornagnon, @Andy: Also, the `input` event is not yet generally supported on contenteditable, so the situation is even worse. – Tim Down May 19 '11 at 10:58
  • i guess the only way to do it is to catch every key event and guess what it was supposed to do :/ running LCS on every keystroke quickly becomes unviable. – nornagon May 19 '11 at 12:25
0

I had a similar problem yesterday and came up with a solution to diff old and new text input values.

The output is like this:

Old value: test test
New value: test w
Change: overwrote 'test' with 'w' at position 5

The script uses window.setInterval() to avoid cross browser problems (see https://stackoverflow.com/a/1949416/727190). This causes some changes to be batched when the user types really fast - this could be a good thing, depends on your situation.

You can, however, easily modify the script to work off events.

http://jsfiddle.net/6zp48/2/

Excerpt from fiddle showing the result of the diff (the findChange() code is too long to paste here):

var changeType = { added: 0, deleted: 1, overwrite: 2 };
var previousValue = '';

window.setInterval(checkChange, 100);

function checkChange() {
    var newValue = $("#input1").val();
    if(newValue != previousValue) {
        showChange(findChange(previousValue, newValue));
        previousValue = newValue;
    }
}

function showChange(result) {
    $("#last-change").html("Prev: " + previousValue + "<br/>Next:" + $("#input1").val() + "<br/>");

    if(result == null)  {
        $("#last-change").html($("#last-change").html() + " no change detected");
        return;
    }

    switch (result.change) {
        case changeType.added:
            $("#last-change").html($("#last-change").html() + "added '" + result.added.text + "' at position " + result.added.position + "<br />");
            break;
        case changeType.deleted:
            $("#last-change").html($("#last-change").html() + "deleted '" + result.lost.text + "' at position " + result.lost.position + "<br />");
            break;
        case changeType.overwrite:
            $("#last-change").html($("#last-change").html() + "overwrote '" + result.lost.text + "' with '" + result.added.text + "' at position " + result.added.position + "<br />");
            break;
    }
}
Community
  • 1
  • 1
ttg
  • 359
  • 1
  • 10
  • 1
    ShareJS has a [neat way of finding changes](https://github.com/josephg/ShareJS/blob/master/src/client/textarea.coffee#L7) in a ` – nornagon Mar 13 '13 at 04:29
  • Nice find! Would that work for things like the user selecting and dragging text around in the textarea, or pasting? – ttg Mar 13 '13 at 04:37
  • 1
    Yep, should work for anything. It won't always find the minimal possible delta or even a very smart delta, but it will always be correct. – nornagon Mar 14 '13 at 07:43
0

Short Answer

$('input').on('keydown keyup click input submit mouseenter', function (e) {
    // Handle e.type
    alert('Type: ' + e.type);
});

Append supported or custom events, it should work. I hope this helps someone See Jquery Documentation for more help. http://api.jquery.com/on/

Pierre
  • 8,397
  • 4
  • 64
  • 80