Selecionar texto no foco de entrada

121

Eu tenho uma entrada de texto. Quando a entrada recebe o foco, quero selecionar o texto dentro da entrada.

Com o jQuery, eu faria da seguinte maneira:

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

Eu procurei ao redor para tentar encontrar a maneira Angular, mas a maioria dos exemplos que estou encontrando está lidando com uma diretiva que está observando uma propriedade modal para uma mudança. Estou assumindo que preciso de uma diretiva que esteja procurando por uma entrada que receba foco. Como eu faria isso?

Billy Coover
fonte
Entendo que você deseja encontrar um 'caminho angular', no entanto, existe algum motivo para você não fazer isso <input type="text" value="test" onclick="this.select()" />?
31417 Josef P.

Respostas:

216

A maneira de fazer isso no Angular é criar uma diretiva personalizada que faça a seleção automática para você.

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

Aplique a diretiva assim:

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

View demo

Update1 : Removida dependência de jQuery.

Atualização2 : Restringir como atributo.

Update3 : funciona no Safari móvel. Permite selecionar parte do texto (requer IE> 8).

Martin
fonte
10
Se você quiser fazer isso sem o jquery, altere element.click para element.bind ('click', function () {...} e element.select () para o elemento [0] .select ()
jack
3
Agradável e elegante. Também restringiria explicitamente a diretiva a ser aplicada como atributo (retornando um objeto literal e a configuração restrict: 'A'), pois essa diretiva visa estender o comportamento de um elemento existente .
Eliran Malka
@ Martin alguma idéia de como fazer isso na página aberta, sem clique do usuário? O problema é que o valor padrão é definido em outro controlador antes do meu selectOnLoadlink de diretiva (). Mas no link (), embora o escopo já esteja preenchido, o elemento DOM ainda não está sincronizado com $ scope, portanto, quando chamo select (), o elemento ainda está vazio e nada foi selecionado. A única maneira de solucionar isso que encontrei é $ timeout, mas sinto que isso pode parar de funcionar com uma nova versão do Angular.
Dzmitry Lazerka
isso funciona bem no desktop / android, mas quando tento o ipad, ele não parece funcionar. Existe um trabalho conhecido por aqui?
ak85
44

Aqui está uma diretiva aprimorada que evita selecionar novamente o texto quando o usuário clica para posicionar o cursor na caixa de entrada.

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
fonte
3
Eu acho que essa resposta é melhor do que o aceito, porque permitem cursor conjunto para alguma posição em texto digitado, mas, como uma directiva têm próprio escopo - i propor para renomear focusedElement variável para isElementFocused e loja lá verdadeira ou falsa
Vladimir Gordienko
2
Eu recebo o TypeError não capturado: indefinido não é uma função "this" para .select (); e sim, o jQuery 1.9.1 está incluído.
Robbie Smith
@RobbieSmith Estou 3 anos atrasado, mas mude todas as instâncias de thispara element[0]e deve funcionar. Também recomendo alterar clickpara focusque o texto seja selecionado se o usuário digitar a entrada em vez de clicar nela.
Lex
40

Esta é uma resposta antiga, para o Angular 1.x

A melhor maneira de fazer isso é usando a ng-clickdiretiva interna:

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

EDITAR:

Como JoshMB lembrou gentilmente; a referência a nós DOM no Angular 1.2+ não é mais permitida. Então, eu mudei $event.target.select()para o controlador:

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

Então no seu controlador:

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

Aqui está um exemplo de violino .

Onur Yıldırım
fonte
2
Tanto quanto eu posso dizer, isso não é mais suportado. Angular gera um erro: "Fazer referência a nós DOM em expressões angulares não é permitido!". Veja este tópico para mais informações: groups.google.com/forum/#!topic/angular/bsTbZ86WAY4 . A abordagem diretiva funciona bem, no entanto.
JoshMB
Você está certo. Este é o caso do Angular 1.2+. Vou atualizar a resposta.
Onur Yıldırım
2
As alterações do DOM devem ser feitas na diretiva ou não?
Piioo 28/10
Por alguma razão, as outras soluções não funcionaram para mim, mas isso funcionou. Acho que o problema era que eu já tinha uma diretiva sobre o elemento ao qual estava adicionando esse evento de clique.
Precastic
Sério, até o onTextClick ($ event) está lançando o erro agora. Além da natureza não intuitiva desta besta, quanto esse inconveniente está nos custando no desempenho?
jcalfee314
15

Nenhuma das soluções propostas funcionou bem para mim. Após uma pesquisa rápida, vim com isso:

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

  }

});

É uma mistura de várias soluções propostas, mas funciona tanto no clique quanto no foco (pense no foco automático) e permite a seleção manual de valor parcial na entrada.

xaralis
fonte
1
Erro de sintaxe corrigido: último}); substituir por: } }; });
Blackfire
Este funciona para o tipo de entrada = "number", o que é ótimo! Obrigado
Louis
Ei, isso funciona para o Ionic no Android, mas não no iOS ... alguma idéia do porquê? Obrigado
Louis
2
Parece que você deixou algum código para trás quando o adaptou do onClick ... para que serve focusedElement?
Langdon
12

Para mim, ng-click não fazia sentido, porque você nunca poderia reposicionar o cursor sem selecionar todo o texto novamente, achei isso irritante. Então é melhor usar o ng-focus, porque o texto é selecionado apenas se a entrada não tiver sido focada. Se você clicar novamente para reposicionar o cursor, o texto será desmarcado, conforme o esperado, e você poderá escrever no meio.

Eu achei que essa abordagem era o comportamento UX esperado.

Use ng-focus

Opção 1: código separado

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

e no controlador

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

Opção 2: como alternativa, você pode associar o código acima a esse "one-liner" (não testei isso, mas deve funcionar)

<input type="text" ng-model="content" ng-focus="$event.target.select()" />
jperelli
fonte
Simples e funciona. Isso também permite o posicionamento do seu cursor no texto selecionado, conforme discutido acima.
Pistola-pete
7

No angular 2, isso funcionou para mim, tanto no Chrome quanto no Firefox:

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

A resposta aceita está usando o evento click, no entanto, se você usar o evento focus, apenas o 1º clique acionará o evento e também será acionado quando algum outro método for usado para focar na entrada (como pressionar a guia ou chamar o foco no código).

Isso também torna desnecessário verificar se o elemento já está focado, como sugere a resposta de Tamlyn.

app.directive('selectOnClick', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.on('focus', function () {
                this.select();
            });
        }
    };
});
OrangeKing89
fonte
No Firefox 38.0.5, clicar no meio do texto primeiro seleciona tudo, mas remove a seleção, para que isso não funcione.
precisa saber é o seguinte
1
Provavelmente isso nunca funcionará de maneira consistente sem demora this.select.
Langdon
6

Nenhuma diretiva é necessária, basta adicionar onfocus="this.select()"javascript nativo ao elemento de entrada ou à área de texto.

Adam Reis
fonte
1
por que tantas pessoas apresentam todas essas respostas complexas, quando a maneira mais fácil está aqui: D Obrigado Adam
SwissCoder
0

Versão modificada que funcionou para mim. Primeiro clique seleciona texto, segundo clique no mesmo elemento desmarca texto

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
fonte