React Native TextInput que aceita apenas caracteres numéricos

106

Preciso ter um TextInputcomponente React Native que só permitirá a inserção de caracteres numéricos (0 - 9). Posso definir o keyboardTypepara o numericqual quase me leva lá para entrada, exceto para o ponto (.). No entanto, isso não impede a colagem de caracteres não numéricos no campo.

O que descobri até agora é usar o OnChangeTextevento para ver o texto inserido. Eu removo todos os caracteres não numéricos do texto. Em seguida, coloque o texto em um campo de estado. Em seguida, atualize o TextInputpor meio de sua Valuepropriedade. Snippet de código abaixo.

<TextInput 
  style={styles.textInput}
  keyboardType = 'numeric'
  onChangeText = {(text)=> this.onChanged(text)}
  value = {this.state.myNumber}
/> 

onTextChanged(text) {
  // code to remove non-numeric characters from text
  this.setState({myNumber: text})
}

Isso parece funcionar, mas parece um hack. Há outra maneira de fazer isso?

Terry
fonte
Nunca fiz esse exemplo funcionar. Você conseguiu resolver de outra forma?
amb
Veja também: stackoverflow.com/questions/40630918/…
hippietrail 01 de
Observe que a partir do React Native 0,54, a maioria das respostas sugeridas aqui estão quebradas: github.com/facebook/react-native/issues/18874 (até pelo menos 0,56, que é a versão mais recente no momento da escrita).
Tomty
1
@sumitkumarpradhan Essa postagem do blog sugere definir o tipo de teclado como 'numérico', o que não impede a entrada de texto. Você pode copiar e colar o que quiser lá.
jmathew
Estou usando keyboardType='numeric'prop em TextInput para mostrar apenas teclado numérico (duh) e também substituindo textos por regex text.replace(/[^0-9]/g, '')como sugerido abaixo para evitar que alguém cole strings dentro de TextInput. Está funcionando bem até agora no React Native v0.62
keshavDulal

Respostas:

30

Essa é a maneira correta de fazer isso até que tal componente (ou atributo no TextInput) seja especificamente desenvolvido.

A web tem o tipo 'número' para o elemento de entrada, mas é baseado na web e o react-native não usa uma visualização da web.

Você pode considerar a criação dessa entrada como um componente de reação por conta própria (talvez chame NumberInput): isso permitirá que você a reutilize ou talvez até mesmo abra o código-fonte, pois você pode criar muitas TextInputs com diferentes filtros / verificadores de valor.

A desvantagem da correção imediata é garantir que o feedback correto seja dado ao usuário para evitar confusão quanto ao que aconteceu com seu valor

Tjorriemorrie
fonte
Como posso definir o código do país. (
Ou
106

Usar um RegExp para substituir qualquer não dígito é mais rápido do que usar um loop for com uma lista de permissões, como fazem outras respostas.

Use para o seu gerenciador onTextChange:

onChanged (text) {
    this.setState({
        mobile: text.replace(/[^0-9]/g, ''),
    });
}

Teste de desempenho aqui: https://jsperf.com/removing-non-digit-characters-from-a-string

Jake Taylor
fonte
Como posso permitir apenas letras do alfabeto inglês usando este método?
CraZyDroiD
2
@CraZyDroiD basta ajustar o regex. Se você quiser apenas corresponder a AZ, precisará de algo comotext.replace(/[^A-Za-z]/g, '')
Jake Taylor
1
Passe também keyboardType='numeric'prop para o campo TextInput.
keshavDulal
94

Você pode fazer assim. Ele só aceitará valores numéricos e terá um limite de 10 números conforme sua preferência.

<TextInput 
   style={styles.textInput}
   keyboardType='numeric'
   onChangeText={(text)=> this.onChanged(text)}
   value={this.state.myNumber}
   maxLength={10}  //setting limit of input
/>

Você pode ver o valor inserido escrevendo o seguinte código em sua página:

{this.state.myNumber}

Na função onChanged (), o código se parece com este:

onChanged(text){
    let newText = '';
    let numbers = '0123456789';

    for (var i=0; i < text.length; i++) {
        if(numbers.indexOf(text[i]) > -1 ) {
            newText = newText + text[i];
        }
        else {
            // your call back function
            alert("please enter numbers only");
        }
    }
    this.setState({ myNumber: newText });
}

Espero que isso seja útil para outros.

Venkatesh Somu
fonte
Pequena correção: onChanged (text) {var newText = ''; números de var = '0123456789'; if (text.length <1) {this.setState ({myNumber: ''}); } para (var i = 0; i <text.length; i ++) {if (numbers.indexOf (text [i])> -1) {newText = newText + text [i]; } this.setState ({myNumber: newText}); }}
Bheru Lal Lohar
1
Boa resposta, mas por que você odeia o número '9'
Stanley Luo
20
Porque 7 odeia 9?
boatcoder
4
Existe alguma maneira de evitar cintilação?
Waltari
vocês são os melhores caras
Khadam Ikhwanus
18

React Native TextInput fornece adereços keyboardType com os seguintes valores possíveis: teclado numérico padrão teclado decimal numérico endereço de e-mail teclado numérico

então, para o seu caso, você pode usar keyboardType = 'number-pad' para aceitar apenas números. Isso não inclui '.'

então,

<TextInput 
  style={styles.textInput}
  keyboardType = 'number-pad'
  onChangeText = {(text)=> this.onChanged(text)}
  value = {this.state.myNumber}
/>

é o que você deve usar no seu caso.

para obter mais detalhes, consulte o link do documento oficial para TextInput: https://facebook.github.io/react-native/docs/textinput#keyboardtype

Ganesh Krishna
fonte
10

Função para validar a entrada:

validateInputs(text, type) {
let numreg = /^[0-9]+$/;
  if (type == 'username') {
    if (numreg.test(text)) {
      //test ok
    } else {
      //test not ok
    } 
  }
}



<TextInput
   onChangeText={text => this.validateInputs(text, 'username')}
/>

Espero que isto seja útil.

Abdul Karim Khan
fonte
essa é a maneira mais eficiente, deve ser seguido em vez do método de loop
Asif Ali
10

Permitir apenas números usando uma expressão regular

<TextInput 
  keyboardType = 'numeric'
  onChangeText = {(e)=> this.onTextChanged(e)}
  value = {this.state.myNumber}
/> 

onTextChanged(e) {
  if (/^\d+$/.test(e.toString())) { 
    this.setState({ myNumber: e });
  }
}

Você pode querer ter mais de uma validação


<TextInput 
  keyboardType = 'numeric'
  onChangeText = {(e)=> this.validations(e)}
  value = {this.state.myNumber}
/> 

numbersOnly(e) {
    return /^\d+$/.test(e.toString()) ? true : false
}

notZero(e) {
    return /0/.test(parseInt(e)) ? false : true
}

validations(e) {
    return this.notZero(e) && this.numbersOnly(e)
        ? this.setState({ numColumns: parseInt(e) })
        : false
}

jasonleonhard
fonte
Não há necessidade de criar essas duas primeiras funções, você pode apenas usar:validations(value: string) { return /0/.test(value) && /^\d+$/.test(value) ? this.setState({ numColumns: value }) : false; }
Frederiko Cesar
2
@FrederikoCesar Dê uma olhada no princípio da responsabilidade única
jasonleonhard
10

Primeira Solução

Você pode usar keyboardType = 'numeric'para teclado numérico.

  <View style={styles.container}>
        <Text style={styles.textStyle}>Enter Number</Text>
        <TextInput
          placeholder={'Enter number here'}
          style={styles.paragraph}
          keyboardType="numeric"
          onChangeText={value => this.onTextChanged(value)}
          value={this.state.number}
        />
      </View>

No primeiro caso, são incluídos sinais de pontuação, por exemplo: - . e -

Segunda Solução

Use expressões regulares para remover sinais de pontuação.

 onTextChanged(value) {
    // code to remove non-numeric characters from text
    this.setState({ number: value.replace(/[- #*;,.<>\{\}\[\]\\\/]/gi, '') });
  }

Por favor, verifique o link do lanche

https://snack.expo.io/@vishal7008/numeric-keyboard

Vishal Dhanotiya
fonte
8

Um lembrete gentil para aqueles que encontraram o problema de que "onChangeText" não pode alterar o valor TextInput como esperado no iOS: isso é na verdade um bug no ReactNative e foi corrigido na versão 0.57.1. Consulte: https://github.com/facebook/react-native/issues/18874

Asa
fonte
Deve ser um comentário e não uma resposta
Haris Nadeem
1
Peço desculpas por não ter reputação suficiente para comentar a questão, então termino com uma resposta, na esperança de chamar a atenção para as pessoas que buscam soluções viáveis.
Asa de
Ponto justo. Vejo que seria necessário 50 reputação para comentar. Infelizmente, não posso remover essa restrição, mas posso dar a você 10 de reputação e, espero, remover algumas das restrições.
Haris Nadeem de
pegue mais 10 para obter provisão de comentários ... Saudações @Wing
Venkatesh Somu
Obrigado :) @VenkateshSomu
Wing
4
<TextInput autoCapitalize={'none'} maxLength={10} placeholder='Mobile Number'  value={this.state.mobile} onChangeText={(mobile) => this.onChanged(mobile)}/>

e método onChanged:

onChanged(text){
   var newText = '';
   var numbers = '0123456789';
   if(text.length < 1){
     this.setState({ mobile: '' });
   }
   for (var i=0; i < text.length; i++) {
        if(numbers.indexOf(text[i]) > -1 ) {
             newText = newText + text[i];
        }
        this.setState({ mobile: newText });
    }
}
Bheru Lal Lohar
fonte
Sua solução, embora resolva meu problema, produz um alerta: "This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property 'type' on a released/nullified synthetic event. This is set to null. If you must keep the original synthetic event around, use event.persist(). See fb>react-event-pooling for more information."não sei o que fazer com isso. Você pode ajudar?
Mike
@Mike algum evento pode causar isso, você pode compartilhar o código do componente via jsfiddle ou rnplay.org
Bheru Lal Lohar
Resolvi isso logo após comentar aqui, mas infelizmente consigo descobrir qual era o problema.
Mike
usar um regex seria uma escolha mais inteligente
Asif Ali
4

Tive o mesmo problema no iOS, usando o evento onChangeText para atualizar o valor do texto digitado pelo usuário, não estava conseguindo atualizar o valor do TextInput, então o usuário ainda veria os caracteres não numéricos que digitou.

Isso ocorria porque, quando um caractere não numérico fosse pressionado, o estado não mudaria, pois this.setState estaria usando o mesmo número (o número que permanecia após a remoção dos caracteres não numéricos) e então TextInput não seria renderizado novamente.

A única maneira que encontrei de resolver isso foi usar o evento keyPress que acontece antes do evento onChangeText, e nele, usar setState para alterar o valor do estado para outro, completamente diferente, forçando a renderização novamente quando o evento onChangeText foi chamado . Não muito feliz com isso, mas funcionou.

Gustavo franco
fonte
4
if (!/^[0-9]+$/.test('123456askm')) {
  consol.log('Enter Only Number');
} else {
    consol.log('Sucess');
}
ANKIT DETROJA
fonte
! / ^ [0-9] + $ /. Test ('123456askm') ele verificará se a string de entrada é numérica ou não .test (Seu valor)
ANKIT DETROJA
1
Olá, por favor, expanda sua resposta sobre por que isso seria uma solução para o problema de OP. Isso ajudará o OP e os futuros visitantes do site. Obrigado!
d_kennetz
3

Eu escrevi esta função que achei útil para evitar que o usuário seja capaz de inserir qualquer coisa diferente da que eu estava disposto a aceitar. Eu também usei keyboardType="decimal-pad"e meuonChangeText={this.decimalTextChange}

  decimalTextChange = (distance) =>
{
    let decimalRegEx = new RegExp(/^\d*\.?\d*$/)
    if (distance.length === 0 || distance === "." || distance[distance.length - 1] === "."
        && decimalRegEx.test(distance)
    ) {
        this.setState({ distance })
    } else {
        const distanceRegEx = new RegExp(/^\s*-?(\d+(\.\d{ 1, 2 })?|\.\d{ 1, 2 })\s*$/)
        if (distanceRegEx.test(distance)) this.setState({ distance })
    }
}

O primeiro ifbloco é o tratamento de erros para o evento em que o usuário exclui todo o texto, ou usa um ponto decimal como o primeiro caractere, ou se tentar colocar mais de uma casa decimal, o segundo ifbloco garante que eles podem digitar como muitos números que quiserem antes da casa decimal, mas apenas até duas casas decimais depois da vírgula.

Andrew M Yasso
fonte
2

Usando um RegExp para substituir qualquer não dígito. Tome cuidado para que o próximo código forneça o primeiro dígito que ele encontrou, portanto, se o usuário colar um parágrafo com mais de um número (xx.xx), o código fornecerá o primeiro número. Isso ajudará se você quiser algo como preço, não um telefone celular.

Use para o seu gerenciador onTextChange:

onChanged (text) {
    this.setState({
        number: text.replace(/[^(((\d)+(\.)\d)|((\d)+))]/g,'_').split("_"))[0],
    });
}
Daniel Jose Padilla Peña
fonte
2

Você pode remover caracteres não numéricos usando regex

onTextChanged (text) {
    this.setState({
        myNumber: text.replace(/\D/g, ''),
    });
}
Anoop
fonte
2
const [text, setText] = useState('');

const onChangeText = (text) => {
  if (+text) {
    setText(text);
  }
};

<TextInput
  keyboardType="numeric"
  value={text}
  onChangeText={onChangeText}
/>

Isso deve salvar de teclados físicos

Zyfar Bektashov
fonte
1

Isso não funciona no IOS, setState -> render -> não altera o texto, mas pode alterar outro. O textinput não pode alterar seu próprio valor quando textOnChange.

A propósito, isso funciona bem no Android.

wv1124
fonte
Explique com o código de exemplo para que outros possam entender.
Bheru Lal Lohar
1

Aqui está minha outra resposta simples para aceitar apenas números na caixa de texto usando expressões regulares.

onChanged(text){
    this.setState({ 
         myNumber: text.replace(/[^0-9]/g, '') 
    });
}
Venkatesh Somu
fonte
1

Para números decimais / flutuantes, tente isso

    onChangeMyFloatNumber(text){
let newText = '';
let numbers = '0123456789.';

for (var i=0; i < text.length; i++) {
    if(numbers.indexOf(text[i]) > -1 ) {
        newText = newText + text[i];
        if(text[i]=="."){
          numbers = '0123456789'
        }
    }
    else {
        // your call back function
        alert("please enter numbers only");
    }
}
this.setState({ MyFloatNumber: newText });

}

abinthomas12914
fonte
0

Bem, esta é uma maneira muito simples de validar um número diferente de 0.

if (+inputNum)

Será NaN se inputNum não for um número ou falso se for 0

Félix Andersson
fonte