Search code examples
jqueryajaxfunctionkeyupwysihtml5

How can I prevent my keyup function to be one character delayed?


I have a textarea, and when I write something, then the text should appear in my resultbox in the same moment.

I am using a keyup function and also tested keydown. But my problem is, that the insert is one character delayed. Or if I write fast it can be more characters.

So for example I write

abcdf

into my textarea and in my result box the result is

abcd

If I add another character, for example z then the f is appearing.

$(document).off("click", ".button").on("click", ".button", function (event) {
  $.ajax({
     url: "update.php",
        data: {
        },
        type: "POST",
        success: function (data) {
            $('.textarea').wysihtml5({
                events: {
                    load: function() {
                        var some_wysi = $('.textarea').data('wysihtml5').editor;
                        $(some_wysi.composer.element).bind('keyup', function(){ 
                         var text = $( ".textarea").val();
                            $(".box[data-select='true']").find($('.result')).val(text);
                        }
                     }
                }
            })
         }
     })
  }

<button class="button">button</button>
<textarea class="textarea"></textarea>
<div class="box" data-select="true"><div class="result"></div></div>

Solution

  • In general, when watching for changes to fields with user input, keyboard events are not the right thing to watch for. Consider the case where the user right-clicks the field and chooses "paste" from the context menu. There's also the issue of the order in which the events occur relative to updating the field's value.

    Instead, use the input event, or (in your specific case) whatever "the value changed" event your WYSIWYG editor provides (which might be change or something else).


    If none of the documented events works, a very imperfect solution might be to delay your update by one event loop cycle via setTimeout.

    // A flag so we don't schedule timer callbacks repeatedly
    var timerPending = false;
    
    // Our callback function
    function handleUpdate() {
        timerPending = false;
        var text = $( ".textarea").val();
        $(".box[data-select='true']").find($('.result')).val(text);
    }
    
    // Hook a bunch of events to try to get as broad a set of notifications as possible
    $(some_wysi.composer.element).bind('keydown keyup keypress input change', function() { 
        // Since we're hooking multiple events, we may get multiple notifications
        // within the same event loop; only setup a timer callback for the first one
        if (!timerPending) {
            timerPending = true;
            setTimeout(handleUpdate, 0);
        }
    }