Give the TextInput onKeyPress Function some time

#TextInput #onKeyPress #debounce #setTimeout

Dedicated to Andreas Kviby.

If you’ve ever inspected the TexInput’s value when the onKeyPress() event handler is triggered, you were probably puzzled by the lack of the last entered character.

Try it yourself with console.log() output - something like this:

export function input1_keyPress(event, $w) { 
   let val = $w('#input1').value;
   console.log(val); 
}

The console output will always be one character behind.

So what gives? You just need to wait a bit for the value to be updated. Use setTimeout() to introduce a small delay:

export function input1_keyPress(event, $w) { 
   setTimeout(() => {
      let val = $w('#input1').value;
      console.log(val); 
   }, 10); // 10 milliseconds works for me
}

Lo and behold, the console output is correct each time it’s triggered.

Even though this works, you might need a more robust delay mechanism. Let’s say for example that you’ve got an autocomplete routine that queries a database or external web service. If the user types too quickly, it might cause overlapping queries - not a pretty sight. So, we can use a more robust mechanism - debounce:

let debounceTimer;
export function input1_keyPress(event, $w) {
   if (debounceTimer) {
      clearTimeout(debounceTimer);
      debounceTimer = undefined;
   }
   debounceTimer = setTimeout(() => {
      let val = $w('#input1').value;
      console.log(val);
      // some sort of query that might overlap execution 
   }, 500); // 500 milliseconds works for me, your mileage may vary
}

As with the simple setTimeout() method above, this introduces a delay which allows the input field to update its value. However, it has an additional advantage in that it prevents calling the service query too quickly in succession. You might need to adjust the timeout based on the query service.

Now, go have fun.

1 Like

Worked perfectly the first time using it ! very easy to read and understand the processes.

@yisrael-wix , I have a stripe integration that is working well but, when someone clicks multiple times its processing multiple charges even though it should just be a single charge. I am using a HTML window with a stripe script running for the CC input, when the HTML post message event occurs we create the charge token and send it to stripe. At this point the box is hidden and a processing message comes up but on slower computers people have double clicked a few times and made it to where we get the multiple charge. I was thinking of adding this to the code to help prevent that. Do you think that would be a good solution? Here is my current code:


export function html1_message(event) {
	let stallType;
	let token = JSON.parse(event.data);
	console.log(token);
	$w("#html1").hide();
	$w("#processing").show();
	//Still need to create a customer with the charge so in the stripe dashbaord customer info is avialble for refunds/chargebacks/etc.  
	charge(token.id, ($w("#cartTotal").value) * 100, $w("#exhibitorName").value + " SCCStalls", (applicationFee), "acct_1Ev8wwFSgCEy4WY1") // manually enter this
		.then((chargeResponse) => {
			console.log("response:" + chargeResponse)
			console.log(applicationFee)
			if (chargeResponse.paid === true) {

I was thinking about a putting a debounce timer with an undetermined amount of time if the

chargeResponse.paid === true

Before I spend a bunch of time beating my head on a table trying to make that work am I on the right track? Is there a better avenue to pursue? Thank you for any kind of help. I really appreciate it.