6

GOAL:

When a user types character in a text box, make a button appear. When the user clears the text box using the backspace key but holds down that key for a few extra seconds, hide the button instantly.

ISSUE:

If a user types in a single character, and uses the backspace to remove it—by holding down the backspace key a few extra seconds—there is a delay before the button is hidden. This only happens when the user typed only one character and then held down the the backspace key without letting go. If instead the user typed multiple characters, and then held down the backspace key until the textbox was empty, there was no delay in hiding the button.

<input type="text" id="tbox"></text>
<button type="button" id="btn"  style="display:none;">push me</button>

$('#tbox').on('keydown keypress keyup',function(){
    if($('#tbox').val() !== '') {
        $('#btn').css({'display':'block'});
    } else {
        $('#btn').css({'display':'none'});
    }
});

JSFIDDLE:

http://jsfiddle.net/odkut0dh/

Bhavesh Jariwala
  • 885
  • 8
  • 27
brooklynsweb
  • 817
  • 3
  • 12
  • 26
  • 2
    use the `input` event http://jsfiddle.net/odkut0dh/1/ – Kaiido Aug 06 '15 at 04:06
  • How about **[this](http://jsfiddle.net/Guruprasad_Rao/odkut0dh/2/)** – Guruprasad J Rao Aug 06 '15 at 04:10
  • 1
    You might be better of using something an event onchange...This wont rely on the keystrokes... For example if select the text with the cursor and right click and cut... There is no keystroke.... So key -down/up/press wont do nothing... so you really need to focus more on onchange in this case... or add that to the list of events as well. – Angry 84 Aug 06 '15 at 04:20
  • @Mayhem, included it to my answer, I hope it's fine with you, forgot about some "browsers" lack of support for `input` event – Kaiido Aug 06 '15 at 04:27
  • Thats fine, rather the user get a detailed answer... I just dont have time atm to write a full example. – Angry 84 Aug 06 '15 at 04:29
  • Thank you for suggesting onchange, however from my understanding, onchange only fires when a user takes action and then removes focus, from the control. I need the result to happen as they are using the control. – brooklynsweb Aug 06 '15 at 13:06
  • See my answer, the bottom about IE<10... basically if you need IE9 or below.. You will need to write a prototype for IE9 via JS – Angry 84 Aug 06 '15 at 13:26
  • @GuruprasadRao, I just checked out your jsfiddle, that solution seemed to work although it did not compensate for the mouse usage. Still, curious how did the use of the setTimout function remove the delay for the keyboard control? I see the delay is set to less than a second; are you overriding the natural response time of the function call? – brooklynsweb Aug 06 '15 at 21:32
  • @brooklynsweb When you use `setTimeout` that will be ran in different thread irrespective of other events happening. So it will maintain its functionality! – Guruprasad J Rao Aug 07 '15 at 03:24

4 Answers4

4

A little walkthrough the situation :

Assuming that <input> value is "x" and you type backspace :
- When the keydown event fires the input's value is still "x".
- When the keypress fires, it still "x".
If you don't release the key :
__ keydown fires again, after some delay, depending on os I guess value is now "".
__ keypress fires again, value is still "".
__ When you release the key, keyup fires, value is "".
If you do release the key :
__ keypress fires directly, value is "".

The solution For IE10+ is to use the input event which will fire when the textEditable element's content has changed or, as suggested by @Mayhem, the change event, which won't even listen for key inputs and has a better browser support than input

$('#tbox').on('input change',function(e){
    if($('#tbox').val() !== '') {
        $('#btn').css({'display':'block'});
    } else {
        $('#btn').css({'display':'none'});
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="tbox"></text>
<button type="button" id="btn"  style="display:none;">push me</button>
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • 1
    Do note, some browsers/element onchange wont trigger until a focus change... But using a combined effort you should get this working... If still having issues i'll try to find time later. – Angry 84 Aug 06 '15 at 04:30
  • launching my favorite IE9 VM to test it out :) han! doesn't pass IE9 test… – Kaiido Aug 06 '15 at 04:31
  • `For select boxes, checkboxes, and radio buttons, the event is fired immediately when the user makes a selection with the mouse, but for the other element types the event is deferred until the element loses focus.` (https://api.jquery.com/change/). So `change` will be triggered only when `input` lost it's focus and which is not what user expecting right? – Bharadwaj Aug 06 '15 at 04:32
  • Actually the input event does exists in IE9 but it does'nt fire for backspace key. – Kaiido Aug 06 '15 at 04:48
  • +1 for having using virtual machine(s) for testing such situations for a true result and for offering descriptions on the events.. – Angry 84 Aug 06 '15 at 09:01
  • Thank you for the walk-through asnwer Kaiido and also the code snippet – brooklynsweb Aug 06 '15 at 21:22
2

As i've aleady made comments on this one, did a quick google and came across this post which might make it a little easier.. Detect all changes to a <input type="text"> (immediately) using JQuery

So i put it into a fiddle here for you to test: Slight Modded Version

The HTML

<input type="text" value="Some Value" id="text1" />
<button id="btn1">Click Me</button>

The JS

 $('#text1').each(function() {
   var elem = $(this);
   elem.data('oldVal', elem.val());
   elem.bind("propertychange change click keyup input paste", function(event){
      if (elem.data('oldVal') != elem.val()) {
          if (elem.val().length == 0 ) {
              $("#btn1").hide();
          } else {
              $("#btn1").show();
          }
       elem.data('oldVal', elem.val());
     }
   });
 });

As i dont have to much time to break this code down into sections... By the looks of it.. You dont need the elem.data... Just the bind event... ... ah seems i decided to shorten the code for you...

http://jsfiddle.net/z2ew3fqz/3/ Using the same HTML...

Shortest version i could make from the example given above

The HTML

<input type="text" value="Some Value" id="text1" />
<button id="btn1">Click Me</button>

The JS

 $('#text1').bind("propertychange change click keyup input paste", function(event){
     if ($(this).val().length == 0 ) {
         $("#btn1").hide();
     } else {
         $("#btn1").show();
     }
 });

I've quickly tested this on chrome.. mouse/function keys all seem to affect it correctly... Other browsers i'll leave upto the OP to test.. Let me know if any issues in a particular browser..

IE10 seems to be the min support for this .. IE9 might be able to have a js prototype done.. But how important is this for support in your project? to support IE<10?

Community
  • 1
  • 1
Angry 84
  • 2,935
  • 1
  • 25
  • 24
1

The Problem is that $('#tbox').val(); is not empty ('') when backspace is pressed. So You have to delay the value check.

When you press down the key, the first thing what happend is that the keydown event is fired, then after that the key action will be performed on the input field.

$('#tbox').on('keydown keypress keyup',function(){
    setTimeout(function () {
          if($('#tbox').val() !== '') {
        $('#btn').css({'display':'block'});
    } else {
        $('#btn').css({'display':'none'});
    }  
},0);

});
basis
  • 158
  • 2
  • 8
0

You can prevent repeating keydown by control it on key up by an global variable:

var allow = true;
$(document).on('keydown', function(e) { 
  if (e.repeat != undefined) {
    allow = !e.repeat;
  }
  if (!allowed) return;
  allowed = false;

  if($('#tbox').val() !== '') {
        $('#btn').css({'display':'block'});
    } else {
        $('#btn').css({'display':'none'});
    }
});

$(document).keyup(function(e) { 
  allowed = true;
});
Siamak Ferdos
  • 3,181
  • 5
  • 29
  • 56