Sélectionnez le texte sur le focus d'entrée

121

J'ai une entrée de texte. Lorsque l'entrée reçoit le focus, je veux sélectionner le texte à l'intérieur de l'entrée.

Avec jQuery, je le ferais de cette façon:

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

J'ai cherché partout pour essayer de trouver la méthode Angular, mais la plupart des exemples que je trouve concernent une directive qui surveille une propriété modale pour un changement. Je suppose que j'ai besoin d'une directive qui surveille une entrée qui reçoit l'attention. Comment pourrais-je faire ça?

Billy Coover
la source
Je comprends que vous voulez trouver une «voie angulaire», mais y a-t-il une raison pour laquelle vous ne le feriez pas <input type="text" value="test" onclick="this.select()" />?
Josef P.

Réponses:

216

La façon de faire cela dans Angular est de créer une directive personnalisée qui effectue la sélection automatique pour vous.

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

Appliquez la directive comme ceci:

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

View demo

Update1 : Dépendance jQuery supprimée.

Update2 : Restreindre comme attribut.

Update3 : fonctionne dans Safari mobile. Permet de sélectionner une partie du texte (nécessite IE> 8).

Martin
la source
10
Si vous voulez faire cela sans jquery, changez element.click en element.bind ('click', function () {...} et element.select () en element [0] .select ()
jack
3
Sympa et élégant. Je limiterais aussi explicitement l'application de la directive en tant qu'attribut (en renvoyant un objet littéral et un paramètre restrict: 'A'), car cette directive vise à étendre le comportement d'un élément existant .
Eliran Malka le
@Martin une idée de comment faire cela sur la page ouverte, sans clic de l'utilisateur? Le problème est que la valeur par défaut est définie dans un autre contrôleur avant ma selectOnLoaddirective link (). Mais dans link (), bien que scope soit déjà rempli, l'élément DOM n'est pas encore synchronisé avec $ scope, donc quand j'appelle select (), element est toujours vide et rien n'est sélectionné. La seule façon de contourner ce que j'ai trouvé est $ timeout, mais je pense que cela peut cesser de fonctionner avec une nouvelle version Angular.
Dzmitry Lazerka
cela fonctionne bien sur le bureau / Android, mais lorsque j'essaye sur iPad, cela ne semble pas fonctionner. Y a-t-il un travail connu ici?
ak85
44

Voici une directive améliorée qui évite de resélectionner le texte lorsque l'utilisateur clique pour positionner le curseur dans la zone de saisie.

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
la source
3
Je pense que cette réponse est meilleure que l' a accepté, car il permet curseur jeu dans une certaine position dans le texte saisi, mais, en tant que directive ont leur propre champ - je propose de renommer focusedElement variable isElementFocused et stocker il vrai ou faux
Vladimir Gordienko
2
J'obtiens Uncaught TypeError: undefined n'est pas une fonction sur "this" pour .select (); et oui jQuery 1.9.1 est inclus.
Robbie Smith
@RobbieSmith J'ai 3 ans de retard, mais changez toutes les instances de thisen element[0]et cela devrait fonctionner. Je recommande également de changer clickpour focusafin que le texte soit sélectionné si l'utilisateur tabule dans l'entrée au lieu de cliquer dessus.
Lex
40

C'est une vieille réponse, pour Angular 1.x

La meilleure façon de le faire est d'utiliser la ng-clickdirective intégrée:

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

ÉDITER:

Comme JoshMB l' a gentiment rappelé; le référencement des nœuds DOM dans Angular 1.2+ n'est plus autorisé. Donc, je suis passé $event.target.select()au contrôleur:

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

Puis dans votre contrôleur:

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

Voici un exemple de violon .

Onur Yıldırım
la source
2
Pour autant que je sache, cela n'est plus pris en charge. Angular renvoie une erreur: "Le référencement des nœuds DOM dans les expressions angulaires est interdit!". Pour plus d'informations, consultez ce fil de discussion: groups.google.com/forum/#!topic/angular/bsTbZ86WAY4 . L'approche directive fonctionne cependant bien.
JoshMB
Vous avez raison. C'est le cas pour Angular 1.2+. Je mettrai à jour la réponse.
Onur Yıldırım
2
Les changements DOM doivent être effectués dans la directive, ou pas?
Piioo
Pour une raison quelconque, les autres solutions n'ont pas fonctionné pour moi, mais cela a fonctionné. Je pense que le problème était que j'avais déjà une directive sur l'élément auquel j'ajoutais cet événement de clic.
Precastic
Sérieusement, même le onTextClick ($ event) lance l'erreur maintenant. Mis à part la nature peu intuitive de cette bête, combien nous coûte cet inconvénient en performance?
jcalfee314
15

Aucune des solutions proposées n'a bien fonctionné pour moi. Après une recherche rapide, j'ai trouvé ceci:

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

  }

});

C'est un mélange de plusieurs solutions proposées, mais fonctionne à la fois sur le clic et la mise au point (pensez à l'autofocus) et permet une sélection manuelle de la valeur partielle dans l'entrée.

Xaralis
la source
1
Erreur de syntaxe corrigée: dernier}); remplacer par: } }; });
Blackfire
Celui-ci fonctionne pour input type = "number", ce qui est génial! Merci
Louis
Hé, cela fonctionne pour Ionic sous Android, mais pas sous iOS ... une idée pourquoi? Merci
Louis
2
On dirait que vous avez laissé du code derrière vous lorsque vous l'avez adapté à partir de onClick ... à quoi ça sert focusedElement?
Langdon
12

Pour moi, ng-click n'avait pas de sens, car vous ne pouviez jamais repositionner le curseur sans sélectionner à nouveau tout le texte, j'ai trouvé que c'était ennuyeux. Ensuite, il est préférable d'utiliser ng-focus, car le texte n'est sélectionné que si l'entrée n'était pas focalisée, si vous cliquez à nouveau pour repositionner le curseur, le texte se désélectionne simplement, comme prévu, et vous pouvez écrire entre les deux.

J'ai trouvé que cette approche était le comportement UX attendu.

Utiliser ng-focus

Option 1: code séparé

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

et en contrôleur

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

Option 2: comme alternative, vous pouvez joindre le code ci-dessus dans ce "one-liner" (je n'ai pas testé cela mais cela devrait fonctionner)

<input type="text" ng-model="content" ng-focus="$event.target.select()" />
jperelli
la source
Simple et ça marche. Cela permet également de positionner votre curseur dans le texte sélectionné, comme indiqué ci-dessus.
pistol-pete
7

Dans angular 2, cela a fonctionné pour moi, à la fois dans Chrome et Firefox:

<input type="text" (mouseup)="$event.target.select()">
guenam
la source
6

La réponse acceptée utilise l'événement click, mais si vous utilisez l'événement focus, seul le premier clic déclenchera l'événement et il se déclenchera également lorsqu'une autre méthode est utilisée pour se concentrer sur l'entrée (comme appuyer sur l'onglet ou appeler le focus dans le code).

Cela rend également inutile de vérifier si l'élément est déjà focalisé comme le suggère la réponse de Tamlyn.

app.directive('selectOnClick', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.on('focus', function () {
                this.select();
            });
        }
    };
});
OrangeKing89
la source
Dans Firefox 38.0.5, cliquer au milieu du texte sélectionne tout d'abord, puis supprime la sélection, donc cela ne fonctionnera pas.
user1338062
1
Cela ne fonctionnera probablement jamais de manière cohérente sans tarder this.select.
Langdon
6

Aucune directive nécessaire, ajoutez simplement du onfocus="this.select()"javascript natif à l'élément d'entrée ou à la zone de texte.

Adam Reis
la source
1
comment se fait-il que tant de gens trouvent toutes ces réponses complexes, alors que le moyen le plus simple est ici: D Merci Adam
SwissCoder
0

Version modifiée qui a fonctionné pour moi. Le premier clic sélectionne le texte, le second clic sur le même élément désélectionne le texte

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
la source
0

Le moyen le plus simple de sélectionner tout le texte sur un clic, un focus ou une tabulation est !!!:

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

...

inputFocused(event: any){
    event.target.select()
}
Dan Ortega
la source