Виберіть текст на фокусі введення


121

У мене є введення тексту. Коли вхід отримує фокус, я хочу вибрати текст всередині введення.

З jQuery я зробив би це так:

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

Я шукав навколо, щоб спробувати знайти кутовий спосіб, але більшість прикладів, які я знаходжу, стосуються директиви, яка переглядає модальне властивість для зміни. Я припускаю, що мені потрібна директива, яка стежить за входом, який отримує фокус. Як би я це зробив?


Я розумію, ви хочете знайти "кутовий шлях", проте чи є причина, яку ви не просто зробили б <input type="text" value="test" onclick="this.select()" />?
Йозеф П.

Відповіді:


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.

Update2 : обмежити як атрибут.

Update3 : працює в мобільному Safari. Дозволяє вибирати частину тексту (вимагає IE> 8).


10
Якщо ви хочете зробити це без jquery, змініть element.click на element.bind ('натисніть', функцію () {...} і element.select () на елемент [0] .select ()
джек

3
Приємно і елегантно. Я також явно обмежував би директиву, яку слід застосовувати як атрибут (шляхом повернення об'єкта в прямому значенні та налаштування restrict: 'A'), оскільки ця директива спрямована на розширення поведінки існуючого елемента .
Еліран Малька

@Martin маєте будь-яку ідею, як це зробити на відкритій сторінці, без натискання користувача? Проблема полягає в тому, що значення за замовчуванням встановлюється в іншому контролері перед моїм selectOnLoadпосиланням на директиву (). Але у link (), хоча область вже заповнена, елемент DOM ще не синхронізований з $ range, тому коли я викликаю select (), елемент все ще порожній і нічого не обрано. Єдиний спосіб подолати те, що я знайшов, - це $ timeout, але я вважаю, що можна перестати працювати з якоюсь новою кутовою версією.
Дмитро Лазерка

це добре працює на робочому столі / андроїді, але коли я пробую на ipad, схоже, це не працює. Чи є тут відома робота?
ak85


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-вузлів у кутовій 1.2+ більше заборонено. Отже, я перейшов $event.target.select()до контролера:

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

Потім у своєму контролері:

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

Ось приклад скрипки .


2
Наскільки я можу сказати, це більше не підтримується. Кутова передає помилку: "Посилання DOM-вузлів у кутових виразах заборонено!". Дивіться цю тему для отримання додаткової інформації: groups.google.com/forum/#!topic/angular/bsTbZ86WAY4 . Однак директивний підхід працює добре.
JoshMB

Ти маєш рацію. Це стосується кутових 1.2+. Я оновлю відповідь.
Onur Yıldırım

2
Зміни DOM повинні бути внесені в директиву, чи ні?
Пійоо

Чомусь інші рішення для мене не спрацювали, але це було. Я думаю, що проблема полягала в тому, що я вже мав директиву щодо елемента, до якого я додавав цю подію клацання.
Передбачливий

Серйозно, зараз навіть onTextClick ($ подія) кидає помилку. Окрім неінтуїтивної природи цього звіра, скільки ця незручність коштує нам у виконанні?
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;
            });
    }

  }

});

Це поєднання декількох запропонованих рішень, але працює як на натискання, так і на фокус (подумайте автофокусування) і дозволяє вручну вибрати часткове значення на вході.


1
Виправлена ​​помилка синтаксису: останній}); замінити на:}}; });
Blackfire

Цей працює для введення type = "число", що чудово! Спасибі
Луї

Гей, це працює для Ionic в Android, але не в iOS ... будь-яка ідея чому? Спасибі
Луї

2
Здається, ви залишили якийсь код позаду, коли ви адаптували його від onClick ... у чому сенс focusedElement?
Ленґдон

12

Для мене ng-клік не мав сенсу, тому що ви ніколи не можете переставити курсор, не вибравши знову весь текст, я виявив, що це дратує. Тоді краще використовувати ng-фокус, тому що текст вибирається лише в тому випадку, якщо введення не було зосередженим, якщо ви знову натискаєте, щоб перемістити курсор, то текст просто знімає вибір, як очікувалося, і ви можете писати між ними.

Я вважав цей підхід очікуваною поведінкою UX.

Використовуйте ng-фокус

Варіант 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()" />

Просто і це працює. Це також дозволяє розташувати курсор у вибраному тексті, як обговорювалося вище.
пістолет-піт

7

У куті 2 це працювало для мене, як у Chrome та Firefox:

<input type="text" (mouseup)="$event.target.select()">

6

Прийнята відповідь використовує подію натискання, але якщо ви використовуєте подію фокусування, лише 1-й клацання призведе до запуску події, а також запуститься, коли використовується якийсь інший метод для фокусування на вході (наприклад, вкладка натискання або виклик фокусу в коді).

Це також робить зайвим перевіряти, чи елемент вже зосереджений, як підказує відповідь Тамліна.

app.directive('selectOnClick', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.on('focus', function () {
                this.select();
            });
        }
    };
});

У Firefox 38.0.5 клацання в середині тексту спочатку вибирає всі, але потім видаляє вибір, тому це не працюватиме.
user1338062

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
        });
    }
}

})

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.