Reputation: 188
i have a textarea where i want to capture the necessary events either them be from the keyboard or the mouse/edit menu. Now, when a user copy pastes a text in the textarea through CTRL-V, processUserInput is called twice, both on keydown and on paste which is undesirable for various reasons.
i have "solved" it this way:
var IsProcessingEvent = false;
$("#textarea").on('click keydown cut paste', processUserInput);
function processUserInput(e) {
if(!IsProcessingEvent) {
IsProcessingEvent = true;
// do the actual processing of user input
IsProcessingEvent = false;
}
}
I was wondering if there is a more elegant solution to this problem.
p.s the onpaste event is needed because the user may copy paste the text through the mouse right click or through the browser edit menu.
thanks in advance!
Upvotes: 4
Views: 2289
Reputation: 2870
You are doing the right way dude. Just better if you change keydown
for keypress
, but you can get your code stylish if you want:
var isProcessingEvent = false;
$("#textarea").on('click keypress cut paste', processUserInput);
function processUserInput(e) {
// Is processing event, so stop here.
if(isProcessingEvent) {
return;
}
isProcessingEvent = true;
// do the actual processing of user input
isProcessingEvent = false;
}
But if I would you, I will use a promisses
to work with your processing of user input, that way you can not freeze all your UI Thread while wainting for the process.
Will be something like this:
$("#textarea").on('click keypress cut paste', processUserInput);
function processUserInput(e) {
// Is processing event, so stop here.
if(processUserInput.working) {
// The user trigger the event while it was processing
processUserInput.doAgain = {
// save context
ctx: this,
// save event
e: e
};
return;
}
processUserInput.working = true;
function finished() {
processUserInput.working = false;
// The process finished but has new changes in the textfield so...
var lastEvent = processUserInput.doAgain;
if (lastEvent) {
processUserInput.doAgain = null;
// Process this guy again
setTimeout(processUserInput.bind(lastEvent.ctx), 0, lastEvent.e);
}
}
function theProcess(e, cb) {
// do my async stuff here
// Unfreeze the click/keydown/cut/past events in the textarea
if (typeof cb === 'function') {
cb();
}
}
setTimeout(theProcess.bind(this), 0, e, finished);
}
This is a example for async, but you may use a async ajax, or web-worker to process your event, this way you would not freeze the UI Thread.
PS.: Timeout don't prevent UI Thread from freeze, it will just put your process in the end of the executing queue.
Ahh another tip!
If you are processing the text in the textarea, is better then you use keypress
instead keydown
because if you get the textarea value in the keydown it will not have changes, but the keypress will get the value changed by the key you are pressing.
http://www.quirksmode.org/dom/events/keys.html
Of course if you still want to use keydown you can defer the processing using the setTimeout
that I made in the example.
Upvotes: 5