Выделить текст в фокусе ввода

121

У меня есть ввод текста. Когда ввод получает фокус, я хочу выделить текст внутри ввода.

С jQuery я бы сделал это так:

<input type="text" value="test" />
$("input[type=text]").click(function() {
    $(this).select();
    // would select "test" in this example
});

Я искал вокруг, пытаясь найти способ Angular, но большинство примеров, которые я нахожу, связаны с директивой, которая отслеживает изменение модального свойства. Я предполагаю, что мне нужна директива, которая отслеживает ввод, который получает фокус. Как мне это сделать?

Билли Кувер
источник
Я понимаю, что вы хотите найти «способ Angular», но есть ли причина, по которой вы бы просто не стали этого делать <input type="text" value="test" onclick="this.select()" />?
Josef P.

Ответы:

216

В Angular это можно сделать, создав настраиваемую директиву, которая выполняет автоматический выбор за вас.

module.directive('selectOnClick', ['$window', function ($window) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.on('click', function () {
                if (!$window.getSelection().toString()) {
                    // Required for mobile Safari
                    this.setSelectionRange(0, this.value.length)
                }
            });
        }
    };
}]);

Примените директиву следующим образом:

<input type="text" value="test" select-on-click />

View demo

Update1 : удалена зависимость jQuery.

Обновление 2 : ограничить как атрибут.

Update3 : работает в мобильном Safari. Позволяет выделить часть текста (требуется IE> 8).

Мартин
источник
10
Если вы хотите сделать это без jquery, замените element.click на element.bind ('click', function () {...} и element.select () на element [0] .select ()
jack
3
Красиво и элегантно. Я бы также явно ограничил применение директивы в качестве атрибута (путем возврата литерала объекта и его настройки restrict: 'A'), поскольку эта директива направлена ​​на расширение поведения существующего элемента .
Элиран Малка
@Martin есть идеи, как это сделать на открытой странице без щелчка пользователя? Проблема в том, что значение по умолчанию установлено в другом контроллере перед моей selectOnLoadдирективой link (). Но в link (), хотя область видимости уже заполнена, DOM элемента еще не синхронизирована с $ scope, поэтому, когда я вызываю select (), элемент все еще пуст и ничего не выделено. Единственный способ обойти, который я нашел, - это $ timeout, но я чувствую, что это может перестать работать с какой-то новой версией Angular.
Дмитрий Лазерка
это хорошо работает на рабочем столе / android, но когда я пытаюсь использовать ipad, похоже, что это не работает. Есть ли здесь известная работа?
ak85 01
44

Вот расширенная директива, которая позволяет избежать повторного выбора текста, когда пользователь щелкает, чтобы поместить курсор в поле ввода.

module.directive('selectOnClick', function () {
    return {
        restrict: 'A',
        link: function (scope, element) {
            var focusedElement;
            element.on('click', function () {
                if (focusedElement != this) {
                    this.select();
                    focusedElement = this;
                }
            });
            element.on('blur', function () {
                focusedElement = null;
            });
        }
    };
})
Тамлин
источник
3
Я думаю , что этот ответ лучше , чем принято, поскольку это позволит устанавливают курсор на какую - то позицию в введенном тексте, но, как директива имеет собственную сферу - я предлагаю переименовать focusedElement переменной isElementFocused и хранить там правду или ложь
Владимир Гордиенко
2
Я получаю Uncaught TypeError: undefined не является функцией на «this» для .select (); и да, jQuery 1.9.1 включен.
Робби Смит,
@RobbieSmith Я опоздал на 3 года, но изменил все экземпляры thisна, element[0]и он должен работать. Я также рекомендую изменить его clickна, focusчтобы текст выделялся, если пользователь вкладывает вкладки во ввод, а не щелкает по нему.
Лекс
40

Это старый ответ для Angular 1.x

Лучший способ сделать это - использовать ng-clickвстроенную директиву:

<input type="text" ng-model="content" ng-click="$event.target.select()" />

РЕДАКТИРОВАТЬ:

Как любезно напомнил JoshMB ; ссылки на узлы DOM в Angular 1.2+ больше не разрешены. Итак, я перешел $event.target.select()в контроллер:

<input type="text" ng-model="content" ng-click="onTextClick($event)" />

Затем в вашем контроллере:

$scope.onTextClick = function ($event) {
    $event.target.select();
};

Вот пример скрипки .

Онур Йылдырым
источник
2
Насколько я могу судить, это больше не поддерживается. Angular выдает ошибку: «Ссылки на узлы DOM в выражениях Angular запрещены!». См. Эту ветку для получения дополнительной информации: groups.google.com/forum/#!topic/angular/bsTbZ86WAY4 . Однако директивный подход работает хорошо.
JoshMB
Ты прав. Так обстоит дело с Angular 1.2+. Обновлю ответ.
Онур Йылдырым
2
Изменения DOM нужно делать в директиве или нет?
Piioo
По какой-то причине другие решения у меня не работали, но это сработало. Я думаю, проблема заключалась в том, что у меня уже была директива для элемента, в который я добавлял это событие щелчка.
Precastic 08
Серьезно, даже onTextClick ($ event) теперь выдает ошибку. Помимо неинтуитивной природы этого зверя, во сколько нам обходятся эти неудобства с точки зрения производительности?
jcalfee314
15

Ни одно из предложенных решений мне не подошло. После быстрого исследования я пришел к следующему:

module.directive('selectOnFocus', function ($timeout) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            var focusedElement = null;

            element.on('focus', function () {
                var self = this;
                if (focusedElement != self) {
                    focusedElement = self;
                    $timeout(function () {
                        self.select();
                    }, 10);
                }
            });

            element.on('blur', function () {
                focusedElement = null;
            });
    }

  }

});

Это сочетание нескольких предложенных решений, но работает как с щелчком, так и с фокусом (подумайте об автофокусе) и позволяет вручную выбирать частичное значение во вводе.

xaralis
источник
1
Исправлена ​​синтаксическая ошибка: последняя}); заменить на: } }; });
Blackfire
Этот работает для input type = "number", и это здорово! Спасибо
Луи
Эй, это работает для Ionic в Android, но не для iOS ... Вы не знаете, почему? Спасибо
Луи
2
Похоже, вы оставили код, когда адаптировали его из onClick ... в чем смысл focusedElement?
Лэнгдон
12

Для меня ng-click не имеет смысла, потому что вы никогда не сможете изменить положение курсора, не выделив весь текст снова, я обнаружил, что это раздражает. Тогда лучше использовать ng-focus, потому что текст выделяется только в том случае, если ввод не был сфокусирован, если вы щелкните еще раз, чтобы переместить курсор, тогда текст просто отменяется, как и ожидалось, и вы можете писать между ними.

Я обнаружил, что такой подход является ожидаемым поведением UX.

Используйте ng-focus

Вариант 1: отдельный код

<input type="text" ng-model="content" ng-focus="onTextFocus($event)" />

и в контроллере

$scope.onTextFocus = function ($event) {
  $event.target.select();
};

Вариант 2: в качестве альтернативы вы можете объединить приведенный выше код в этот «однострочный» (я не тестировал это, но он должен работать)

<input type="text" ng-model="content" ng-focus="$event.target.select()" />
jperelli
источник
Просто и это работает. Это также позволяет позиционировать курсор внутри выделенного текста, как описано выше.
Пистолет-Пит
7

В angular 2 это сработало для меня, как в Chrome, так и в Firefox:

<input type="text" (mouseup)="$event.target.select()">
guenam
источник
6

В принятом ответе используется событие щелчка, однако, если вы используете событие фокуса, только 1-й щелчок вызовет событие, и оно также срабатывает, когда используется какой-либо другой метод для фокусировки на вводе (например, нажатие вкладки или вызов фокуса в коде).

Это также делает ненужным проверять, сфокусирован ли элемент уже, как предлагает ответ Тамлина.

app.directive('selectOnClick', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.on('focus', function () {
                this.select();
            });
        }
    };
});
OrangeKing89
источник
В Firefox 38.0.5 щелчок в середине текста сначала выделяет все, но затем удаляет выделение, так что это не сработает.
user1338062 04
1
Вероятно, это никогда не сработает постоянно, без задержек this.select.
Лэнгдон
6

Никаких директив не требуется, просто добавьте onfocus="this.select()"собственный javascript в элемент ввода или текстовую область.

Адам Рейс
источник
1
почему так много людей придумывают все эти сложные ответы, когда самый простой способ здесь: D Спасибо, Адам
SwissCoder
0

Модифицированная версия, которая работала у меня. Первый щелчок выделяет текст, второй щелчок по тому же элементу отменяет выделение текста

module.directive('selectOnClick', function ($timeout) {
return {
    restrict: 'A',
    link: function (scope, element, attrs) {
        var prevClickElem = null; //Last clicked element
        var ignorePrevNullOnBlur = false; //Ignoring the prevClickElem = null in Blur massege function

        element.on('click', function () {
            var self = this;
            if (prevClickElem != self) { //First click on new element
                prevClickElem = self; 
                $timeout(function () { //Timer
                    if(self.type == "number")
                        self.select();
                    else
                        self.setSelectionRange(0, self.value.length)
                }, 10);
            }
            else { //Second click on same element
                if (self.type == "number") {
                    ignorePrevNullOnBlur = true;
                    self.blur();
                }
                else
                    self.setSelectionRange(self.value.length, self.value.length); //deselect and set cursor on last pos
            }
        });

        element.on('blur', function () {
            if (ignorePrevNullOnBlur == true)
                ignorePrevNullOnBlur = false; //blur called from code handeling the second click 
            else
                prevClickElem = null; //We are leaving input box
        });
    }
}

})

Ола
источник
0

Самый простой способ выделить весь текст при нажатии, фокусе или табуляции !!!:

<input (focus)="inputFocused($event)">

...

inputFocused(event: any){
    event.target.select()
}
Дэн Ортега
источник