Zaznacz tekst w fokusie wprowadzania

121

Mam wpisywanie tekstu. Kiedy wejście jest fokusem, chcę zaznaczyć tekst wewnątrz wejścia.

Z jQuery zrobiłbym to w ten sposób:

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

Szukałem wokół, aby spróbować znaleźć sposób Angular, ale większość przykładów, które znajduję, dotyczy dyrektywy, która obserwuje właściwość modalną pod kątem zmiany. Zakładam, że potrzebuję dyrektywy, która obserwuje dane wejściowe, które są skupione. Jak bym to zrobił?

Billy Coover
źródło
Rozumiem, że chcesz znaleźć „kątową drogę”, ale czy jest jakiś powód, dla którego byś tego nie zrobił <input type="text" value="test" onclick="this.select()" />?
Josef P.

Odpowiedzi:

216

Sposobem na to w Angular jest utworzenie niestandardowej dyrektywy, która dokonuje automatycznego wyboru za Ciebie.

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

Zastosuj dyrektywę w następujący sposób:

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

View demo

Update1 : Usunięto zależność jQuery.

Aktualizacja2 : Ogranicz jako atrybut.

Aktualizacja 3 : Działa w mobilnym Safari. Umożliwia zaznaczenie części tekstu (wymaga IE> 8).

Jaskółka oknówka
źródło
10
Jeśli chcesz to zrobić bez jquery, zmień element.click na element.bind ('click', function () {...} i element.select () na element [0] .select ()
jack
3
Ładnie i elegancko. Chciałbym również wyraźnie ograniczyć stosowanie dyrektywy jako atrybutu (zwracając literał obiektu i ustawienie restrict: 'A'), ponieważ ta dyrektywa ma na celu rozszerzenie zachowania istniejącego elementu .
Eliran Malka,
@Martin ma jakiś pomysł, jak to zrobić na otwartej stronie, bez klikania przez użytkownika? Problem polega na tym, że wartość domyślna jest ustawiana w innym kontrolerze przed moją selectOnLoaddyrektywą link (). Ale w link (), mimo że zakres jest już wypełniony, element DOM nie jest jeszcze zsynchronizowany z $ scope, więc kiedy wywołuję select (), element jest nadal pusty i nic nie jest zaznaczone. Jedynym sposobem obejścia tego problemu jest $ timeout, ale wydaje mi się, że może przestać działać z jakąś nową wersją Angulara.
Dzmitry Lazerka
działa to dobrze na komputerze stacjonarnym / Androidzie, ale kiedy próbuję na iPadzie, wydaje się, że nie działa. Czy jest tu znana praca?
ak85
44

Oto ulepszona dyrektywa, która pozwala uniknąć ponownego zaznaczania tekstu, gdy użytkownik kliknie, aby ustawić kursor w polu wprowadzania.

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;
            });
        }
    };
})
Tamlyn
źródło
3
Myślę, że ta odpowiedź jest lepsza niż zaakceptowane, ponieważ pozwalają przesuwać kursor na jakiejś pozycji w wprowadzonego tekstu, ale, jak dyrektywy mają własne możliwości - proponuję zmienić nazwę focusedElement zmiennej isElementFocused i przechowywać tam prawdziwe lub fałszywe
Vladimir Gordienko
2
Otrzymuję Uncaught TypeError: undefined nie jest funkcją w "this" dla .select (); i tak jest jQuery 1.9.1.
Robbie Smith
@RobbieSmith Jestem spóźniony o 3 lata, ale zmień wszystkie wystąpienia thisna element[0]i powinno działać. Zalecam również zmianę clickna focus, aby tekst był zaznaczany, jeśli użytkownik wejdzie w wejście zamiast klikania.
Lex
40

To stara odpowiedź dla Angular 1.x

Lepszym sposobem na to jest użycie ng-clickwbudowanej dyrektywy:

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

EDYTOWAĆ:

Jak uprzejmie przypomniał JoshMB ; odwoływanie się do węzłów DOM w Angular 1.2+ nie jest już dozwolone. Więc przeniosłem $event.target.select()się do kontrolera:

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

Następnie w kontrolerze:

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

Oto przykładowe skrzypce .

Onur Yıldırım
źródło
2
O ile wiem, nie jest to już obsługiwane. Angular generuje błąd: „Odwoływanie się do węzłów DOM w wyrażeniach Angular jest niedozwolone!”. Więcej informacji znajdziesz w tym wątku: groups.google.com/forum/#!topic/angular/bsTbZ86WAY4 . Jednak podejście dyrektywne działa dobrze.
JoshMB
Masz rację. Tak jest w przypadku Angular 1.2+. Zaktualizuję odpowiedź.
Onur Yıldırım
2
Zmiany DOM powinny być wprowadzone w dyrektywie, czy nie?
Piioo
Z jakiegoś powodu inne rozwiązania nie działały dla mnie, ale tak się stało. Myślę, że problem polegał na tym, że miałem już dyrektywę dotyczącą elementu, do którego dodałem to zdarzenie kliknięcia.
Precyzyjny
Poważnie, teraz nawet onTextClick ($ event) zgłasza błąd. Pomijając nieintuicyjną naturę tej bestii, ile kosztuje nas ta niedogodność w działaniu?
jcalfee314
15

Żadne z proponowanych rozwiązań nie sprawdziło się dla mnie. Po szybkich poszukiwaniach wymyśliłem to:

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

  }

});

Jest to mieszanka kilku proponowanych rozwiązań, ale działa zarówno na kliknięcie, jak i na fokus (pomyśl o autofokusie) i pozwala na ręczny wybór wartości częściowej w wejściu.

xaralis
źródło
1
Poprawiony błąd składniowy: ostatnia}); zastąpiony przez: } }; });
Blackfire
Ten działa dla input type = "number", co jest świetne! Dzięki
Louis
Hej, to działa na Ionic na Androidzie, ale nie na iOS ... Masz jakiś pomysł, dlaczego? Dzięki
Louis
2
Wygląda na to, że zostawiłeś jakiś kod, kiedy dostosowałeś go z onClick ... o co chodzi focusedElement?
Langdon
12

Dla mnie ng-click nie miało sensu, ponieważ nigdy nie można było zmienić położenia kursora bez ponownego zaznaczenia całego tekstu, stwierdziłem, że to anno. Wtedy lepiej jest użyć ng-focus, ponieważ tekst jest zaznaczony tylko wtedy, gdy wejście nie było fokusem, jeśli klikniesz ponownie, aby zmienić położenie kursora, tekst po prostu odznacza się, zgodnie z oczekiwaniami, i możesz pisać pomiędzy.

Uważam, że to podejście jest oczekiwanym zachowaniem UX.

Użyj ng-focus

Opcja 1: oddzielny kod

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

i w kontrolerze

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

Opcja 2: jako alternatywę możesz dołączyć powyższy kod do tego „jednowierszowego” (nie testowałem tego, ale powinno działać)

<input type="text" ng-model="content" ng-focus="$event.target.select()" />
jperelli
źródło
Proste i działa. Pozwala to również na umieszczenie kursora w wybranym tekście, jak omówiono powyżej.
pistol-pete
7

W Angular 2 zadziałało to dla mnie, zarówno w Chrome, jak i Firefox:

<input type="text" (mouseup)="$event.target.select()">
guenam
źródło
6

Zaakceptowaną odpowiedzią jest użycie zdarzenia click, jednak jeśli użyjesz zdarzenia focus, tylko pierwsze kliknięcie uruchomi zdarzenie, a także zostanie uruchomione, gdy zostanie użyta inna metoda do skupienia się na danych wejściowych (np. Naciśnięcie tabulatora lub wywołanie fokusa w kodzie).

To również sprawia, że ​​nie ma potrzeby sprawdzania, czy element jest już skupiony, jak sugeruje odpowiedź Tamlyna.

app.directive('selectOnClick', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.on('focus', function () {
                this.select();
            });
        }
    };
});
OrangeKing89
źródło
W przeglądarce Firefox 38.0.5 kliknięcie na środku tekstu najpierw zaznacza wszystko, a następnie usuwa zaznaczenie, więc to nie zadziała.
user1338062
1
To prawdopodobnie nigdy nie będzie działać konsekwentnie bez opóźnień this.select.
Langdon
6

Żadne dyrektywy nie są potrzebne, po prostu dodaj onfocus="this.select()"natywny javascript do elementu wejściowego lub obszaru tekstowego.

Adam Reis
źródło
1
dlaczego tak wiele osób
wymyśla
0

Zmodyfikowana wersja, która działała dla mnie. Pierwsze kliknięcie zaznacza tekst, drugie kliknięcie tego samego elementu odznacza tekst

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

})

Ola
źródło
0

Najłatwiejszym sposobem zaznaczenia całego tekstu po kliknięciu, fokusie lub karcie jest !!!:

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

...

inputFocused(event: any){
    event.target.select()
}
Dan Ortega
źródło