37

I have the same problem as the user in this question, which is due to this bug in Webkit. However, the workaround provided will not work for my app. Let me re-state the problem so that you don't have to go read another question:

I am trying to select all the text in a textarea when it gets focus. The following jQuery code works in IE/FF/Opera:

$('#out').focus(function(){
  $('#out').select();
});

However, in Chrome/Safari the text is selected--very briefly--but then the mouseUp event is fired and the text is deselected. The following workaround is offered in the above links:

$('#out').mouseup(function(e){
  e.preventDefault();
});

However, this workaround is no good for me. I want to select all text only when the user gives the textarea focus. He must then be able to select only part of the text if he chooses. Can anyone think of a workaround that still meets this requirement?

Community
  • 1
  • 1
Jenni
  • 1,668
  • 4
  • 20
  • 28
  • 5
    A big +1 for spotting the obvious glaring flaw in the most commonly-suggested solution to the problem. – SDC Sep 21 '12 at 10:48

9 Answers9

29

How about this?

$('#out').focus(function () {
    $('#out').select().mouseup(function (e) {
        e.preventDefault();
        $(this).unbind("mouseup");
    });
});
tcooc
  • 20,629
  • 3
  • 39
  • 57
  • 9
    Probably `.one()` is a better way here. – ValeriiVasin Sep 10 '12 at 08:52
  • +1. I don't get why so many people think the basic `preventDefault()` fix is sufficient. It clearly has severe flaws, and yet it's being suggested as the solution everywhere you look. Thank you for solving it. (though yes, I agree with @InviS that `.one()` might be a better way of doing it) – SDC Sep 21 '12 at 10:53
  • 1
    .one() would be better and this doesn't handle tabbed focus very well. – Jimmy Bosse May 08 '13 at 15:48
  • 1
    Here's how to do this using jQuery's `.one()` as @InviS suggests: `$('#out').focus(function () { $('#out').select().one('mouseup', function (e) { e.preventDefault(); }); });` – evanrmurphy Jun 27 '14 at 20:42
25

The accepted answer (and basically every other solution I found so far) does not work with keyboard focus, i. e. pressing tab, at least not in my Chromium 21. I use the following snippet instead:

$('#out').focus(function () {
  $(this).select().one('mouseup', function (e) {
    $(this).off('keyup');
    e.preventDefault();
  }).one('keyup', function () {
    $(this).select().off('mouseup');
  });
});

e.preventDefault() in the keyup or focus handler does not help, so the unselecting after a keyboard focus seems to not happen in their default handlers, but rather somewhere between the focus and keyup events.

As suggested by @BarelyFitz, it might be better to work with namespaced events in order to not accidentally unbind other event handlers. Replace 'keyup' with 'keyup.selectText' and 'mouseup' with 'mouseup.selectText' for that.

Adrian Heine
  • 4,051
  • 2
  • 30
  • 43
  • 4
    When you unbind events, you could inadvertently unbind other handlers that might be on the input. To prevent this you could use a namespace such as "mouseup.selectText" instead of "mouseup", then only your single event handler will be removed. – BarelyFitz Jul 10 '14 at 13:22
  • Combined with the namespace hint this is the best solution I've found yet for this sticky wicket and I commend it to the house. – dartacus Jan 12 '16 at 11:49
4

Why not simply:

$('#out').focus(function(){
    $(this).one('mouseup', function() {
        $(this).select();
    });
});

Seems to work in all major browsers...

Barbarab
  • 41
  • 1
  • 4
    This worked for me. It's worth noting that it doesn't seem to work when you focus on an input through code. To get around this, I use `$('#element').select().focus()` instead of `$('#element').focus()`. – Amy Barrett Apr 28 '16 at 08:40
4

A very slightly different approach would be to separate the focus event from the mouse sequence. This works really nicely for me - no state variables, no leaked handlers, no inadvertent removal of handlers, and it works with click, tab, or programmatic focus. Code and jsFiddle below -

$('#out').focus(function() {
    $(this).select();
});
$('#out').on('mousedown.selectOnFocus', function() {
    if (!($(this).is(':focus'))) {
        $(this).focus();
        $(this).one('mouseup.selectOnFocus', function(up) {
            up.preventDefault();
        });
    }
});

https://jsfiddle.net/tpankake/eob9eb26/27/

tpankake
  • 366
  • 2
  • 3
2
onclick="var self = this;setTimeout(function() {self.select();}, 0);"
Terje
  • 59
  • 1
  • This answer inspired: `$("#one").on('focus', null, function() { var $that = $(this); setTimeout(function() { $that.select(); }, 0); });` – Jimmy Bosse May 08 '13 at 15:44
2

Select the text before putting the focus on the input box.

$('#out').select().focus();
finpup
  • 21
  • 3
2

Make a bool. Set it to true after a focus event and reset it after a mouse up event. During the mouse up, if it's true, you know the user just selected the text field; therefore you know you must prevent the mouse up from happening. Otherwise, you must let it pass.

var textFieldGotFocus = false;

$('#out').focus(function()
{
    $('#out').select();
    textFieldGotFocus = true;
});

$('#out').mouseup(function(e)
{
    if (textFieldGotFocus)
        e.preventDefault();
});

$(document).mouseup(function() { textFieldGotFocus = false; });

It's important that you put the mouseup listener that resets the variable on document, since it's not guaranteed that the user will release the mouse button over the text field.

zneak
  • 134,922
  • 42
  • 253
  • 328
  • thanks! this inspired an even simpler idea: instead of a listener on document.mouseup, just set the flag to false on out.mouseup: `if(textFieldGotFocus){ e.preventDefault(); textFieldGotFocus = false;}` – Jenni Aug 01 '10 at 02:25
  • Gosh no. global vars + event handling == recipe for trouble. – SDC Sep 21 '12 at 10:52
0

digitalfresh's solution is mostly there, but has a bug in that if you manually trigger .focus() using JS (so not using a click), or if you tab to the field, then you get an unwanted mouseup event bound - this causes the first click that should deselect the text to be ignored.

To solve:

var out = $('#out');
var mouseCurrentlyDown = false;

out.focus(function () {
  out.select();

  if (mouseCurrentlyDown) {
    out.one('mouseup', function (e) {
      e.preventDefault();
    });  
  }
}).mousedown(function() {
  mouseCurrentlyDown = true;
});

$('body').mouseup(function() {
  mouseCurrentlyDown = false;
});

Note: The mouseup event should be on body and not the input as we want to account for the user mousedown-ing within the input, moving the mouse out of the input, and then mouseup-ing.

Jai
  • 897
  • 9
  • 15
0

tpankake's answer converted to a reusable jQuery function..
(If you upvote this, please also upvote his answer)

Load the following AFTER loading the jQuery library:

$.fn.focusSelect = function () {
    return this.each(function () {
        var me = $(this);
        me.focus(function () {
            $(this).select();
        });
        me.on('mousedown.selectOnFocus', function () {
            var me2 = $(this);
            if (me2.is(':focus') === false) {
                me2.focus();
                me2.one('mouseup.selectOnFocus', function (up) {
                    up.preventDefault();
                });
            }
        });
    });
};

Use it like this:

$(document).ready(function () {
    // apply to all inputs on the page:
    $('input[type=text]').focusSelect();

    // apply only to one input
    $('#out').focusSelect();
});
Drew
  • 4,215
  • 3
  • 26
  • 40