23

I have a simple past event as

document.getElementById('paste_area').addEventListener('paste', function() {
    document.getElementById('notice').innerHTML='Text was successfully pasted!';
    alert('Pasted');
}, true);

A working example can be found here http://jsfiddle.net/XEQzz/

The alert and notice will appear before pasting. How can I delay the alert action to happen after paste event has been actually completed?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Googlebot
  • 15,159
  • 44
  • 133
  • 229
  • 1
    Use `setTimeout` (with a minimal delay such as zero) to defer the execution of the script. – Rob W Dec 15 '12 at 18:46
  • 1
    you could set up your own paste handler using preventDefault() (or IE equivalent variable - I forget the name), but an easier way is to use an input event http://stackoverflow.com/a/241158/1162141 since (IIRC) it can also handle dropping dragged text – technosaurus Dec 15 '12 at 19:09
  • @technosaurus `paste handler` is not bullet proof and cross-browser. For example, FireFox does not allow accessing the paste data. – Googlebot Dec 15 '12 at 19:17

5 Answers5

34

You could put your alert in a setTimeout.

setTimeout(function() {alert('Pasted');}, 0);

This will delay the code until after the value has updated.

Just keep in mind that this in the setTimeout callback will have a different value than that in the enclosing environment.

If you'll need a reference to the outer this, which will be the element, then reference it in a variable...

var self = this;
setTimeout(function() {alert(self.value);}, 0);

Or use .bind() (Supported in most browsers that support addEventListener. Older Safari didn't support it.)...

setTimeout(function() {alert(this.value);}.bind(this), 0);
I Hate Lazy
  • 47,415
  • 13
  • 86
  • 77
3

For updating own value

 $(".number").on("paste", function (e) {
        var Value = e.originalEvent.clipboardData.getData('text');
        var Self=this
        setTimeout(function () {
            if (Value != Value.replace(/[^\d\.]/g, "")) {
                $(Self).val(Value.replace(/[^\d\.]/g, ""));
            }
        }, 0);
    });
VISHMAY
  • 699
  • 5
  • 20
  • 1
    `clipboardData` is a cleaner approach, but IE unfortunately does not support it – Post Self Mar 31 '20 at 13:26
  • 1
    The function **`event.clipboardData.getData("text")`** works well without timeout. However, it should be noted that **it returns only the value that is being pasted, not the new value of an input element.** E.g.: the input element's value was initially "my value"; then you paste "SuPeR" somewhere in the middle, and the new value is "my SuPeRvalue"; in this case, `event.clipboardData.getData("text")`will return only "SuPeR". And if there's a need to get the updated input elemtnt's value — NOT the pasted value — `setTimeout` is the only option, though. – Roman Karagodin Feb 04 '21 at 13:10
3

I usually do like this to mimic an onafterpaste.

I have a special function called "onafterpaste" and I use it like this:

onpaste="onafterpaste(myFunction, this)"

As you see, it also accepts an extra parameter which will be used when myFunction is called.

See (and try it out in) the following live snippet:

function onafterpaste(f,elm) {
  setTimeout(function() {f(elm)},0);
}

function  myFunction(elm) {
  alert('After the paste, the input has the following text:\r\n\r\n'+elm.value);
}
<p>Paste something down here:</p>
<input type="text" onpaste="onafterpaste(myFunction,this)" value="The original text">
Magnus
  • 1,584
  • 19
  • 14
2

setTimeout seems the best option and you can use something like this to generalise

// object definition

    function PasteMonitor(element)
    {
        if(typeof element == "string")
        {
            this.target = document.getElementById(element);
        }
        else if(typeof element == "object" || typeof element == "function")
        {
            this.target = element;
        }

        if(this.target != null && this.target != undefined)
        {
            this.target.addEventListener('paste',this.inPaste.bind(this),false);
            this.target.addEventListener('change',this.changed.bind(this),false);
        }
        this.oldstate = "";
    }
    PasteMonitor.prototype = Object.create({},{
        pasted:{ value: false, enumerable: true, configurable: true, writable: true },
        changed:{ value: function(evt){
            //elements content is changed
            if(typeof this.onChange == "function")
            {
                this.onChange(evt);
            }
            if(this.pasted)
            {
                if(typeof this.afterPaste == "function")
                {
                    this.afterPaste(evt);
                    this.pasted = false;
                }
            }
        }, enumerable: true, configurable: true, writable: true },
        inPaste:{ value: function(evt){
            var cancelPaste = false;
            if(typeof this.beforePaste == "function")
            {
                // process pasted data
                cancelPaste = this.beforePaste(evt);
            }
            if(cancelPaste == true)
            {
                evt.preventDefault();
                return false;
            }
            this.pasted = true;
            setTimeout(function(){
                var evt = document.createEvent("HTMLEvents");
                evt.initEvent("change", false, true);
                this.target.dispatchEvent(evt);
            }.bind(this),0);
        }, enumerable: true, configurable: true, writable: true }
    })
    PasteMonitor.prototype.constructor = PasteMonitor;

//PasteMonitor usage

    //var element = document.getElementById('paste_area');
    var msgArea = document.getElementById('message');
    var myMonitor = new PasteMonitor("paste_area");
    //or use and object as argument => var myMonitor = new PasteMonitor(element);

    myMonitor.onChange = function(evt){
        if(this.pasted)
        {
            //do something on paste change
            msgArea.innerHTML = "onChange by paste";
            this.oldstate = this.target.value;
        }
        //check to prevent processing change event when the element loses focus if the change is done by paste
        else if(this.target.value != this.oldstate)
        {
            msgArea.innerHTML = "onChange by typing";
        }
    };
    myMonitor.afterPaste = function(evt){
       // do something after paste
        msgArea.innerHTML = "afterPaste";
    };
    myMonitor.beforePaste = function(evt){
        // do something before the actual paste
        msgArea.innerHTML = "beforePaste";
        //return true to prevent paste
        return false;
    };
Atlantrix
  • 149
  • 1
  • 8
-2

Is paste_area an input? input is also an event.

Here's a working example: https://jsfiddle.net/9shcqnxo/

document.getElementById('paste_area').addEventListener('input', function() {
    let inArea = document.getElementById('paste_area').value;
    document.getElementById('notice').innerHTML='Text change: ' + inArea;
    alert(inArea);

});
Zamicol
  • 4,626
  • 1
  • 37
  • 42
  • Not working: also the `input` event fires _before_ the pasted content appears in the DOM element. – Luca Fagioli Jan 28 '22 at 19:41
  • Looks working to me: http://jsfiddle.net/9shcqnxo/ – Zamicol Jan 28 '22 at 20:05
  • I am trying from Chrome, and your snippet confirms that it does not work: the alert shows up before the text is actually pasted in the textfield. – Luca Fagioli Jan 29 '22 at 09:12
  • The alert indeed happens after paste (as shown by being populated with the correct data) but not after the GUI update. See https://stackoverflow.com/a/42986563/1923095 – Zamicol Jan 30 '22 at 20:25
  • The alert in your snippet happens *before* the paste. Which is exactly the problem the OP is trying to solve. Your answer does not. – Luca Fagioli Jan 31 '22 at 10:05
  • Here it is working as a gif: imgur.com/a/1mMdRDc Getting the value is synchronous and the alert is synchronous, but the GUI draw is asynchronous. – Zamicol Feb 01 '22 at 17:11
  • This approach does not solve the problem in any case, so case closed. – Luca Fagioli Feb 03 '22 at 20:24