React Native TextInput que solo acepta caracteres numéricos

101

Necesito tener un TextInputcomponente React Native que solo permita ingresar caracteres numéricos (0 - 9). Puedo ajustar la keyboardTypea numericla que casi me lleva allí para la entrada a excepción del punto (.). Sin embargo, esto no hace nada para dejar de pegar caracteres no numéricos en el campo.

Lo que se me ocurrió hasta ahora es usar el OnChangeTextevento para ver el texto ingresado. Elimino los caracteres no numéricos del texto. Luego ponga el texto en un campo de estado. Luego actualice la propiedad a TextInputtravés de ella Value. Fragmento de código a continuación.

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

Esto parece funcionar, pero parece un truco. Hay otra manera de hacer esto?

Terry
fuente
Nunca conseguí que este ejemplo funcionara. ¿Lograste resolverlo de otra manera?
amb
Ver también: stackoverflow.com/questions/40630918/…
hippietrail
Tenga en cuenta que a partir de React Native 0.54, la mayoría de las respuestas sugeridas aquí están rotas: github.com/facebook/react-native/issues/18874 (hasta al menos 0.56, que es la versión más reciente en el momento de escribir este artículo).
Tomty
1
@sumitkumarpradhan Esa publicación de blog sugiere configurar el tipo de teclado en 'numérico', lo que en realidad no impide la entrada de texto. Puedes copiar y pegar lo que quieras allí.
jmathew
Estoy usando keyboardType='numeric'prop en TextInput para mostrar solo el teclado numérico (duh) y también reemplazando textos con expresiones regulares text.replace(/[^0-9]/g, '')como se sugiere a continuación para evitar que alguien pegue cadenas dentro de TextInput. Está funcionando bien hasta ahora en React Native v0.62
keshavDulal

Respuestas:

28

Esa es la forma correcta de hacerlo hasta que tal componente (o atributo en TextInput) se desarrolle específicamente.

La web tiene el tipo 'número' para el elemento de entrada, pero eso está basado en web y react-native no usa una vista web.

Podría considerar crear esa entrada como un componente de reacción por sí solo (tal vez llamar a NumberInput): eso le permitirá reutilizarlo o tal vez incluso abrirlo como fuente, ya que puede crear muchos TextInputs que tienen diferentes filtros / verificadores de valor.

La desventaja de la corrección inmediata es garantizar que se brinde una retroalimentación correcta al usuario para evitar confusión sobre lo que sucedió con su valor.

Tjorriemorrie
fuente
¿Cómo puedo configurar con el código de país? (Es decir, puedo configurar el código de país con cualquier accesorio en el componente de entrada de texto)
sejn
101

Usar una expresión regular para reemplazar cualquier dígito que no sea es más rápido que usar un bucle for con una lista blanca, como lo hacen otras respuestas.

Use esto para su controlador onTextChange:

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

Prueba de rendimiento aquí: https://jsperf.com/removing-non-digit-characters-from-a-string

Jake Taylor
fuente
¿Cómo puedo permitir solo letras en el alfabeto inglés usando este método?
CraZyDroiD
2
@CraZyDroiD simplemente ajusta la expresión regular. Si solo desea igualar AZ, necesitará algo comotext.replace(/[^A-Za-z]/g, '')
Jake Taylor
1
También pase keyboardType='numeric'prop al campo TextInput.
keshavDulal
91

Puedes hacerlo así. Solo aceptará valores numéricos y se limitará a 10 números según lo desee.

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

Puede ver el valor ingresado escribiendo el siguiente código en su página:

{this.state.myNumber}

En la función onChanged (), el código se ve así:

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 esto sea útil para otros.

Venkatesh Somu
fuente
Pequeña corrección: onChanged (text) {var newText = ''; var numeros = '0123456789'; if (text.length <1) {this.setState ({myNumber: ''}); } for (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
Buena respuesta, pero ¿por qué odias el número '9'
Stanley Luo
19
¿Porque el 7 odia el 9?
Boatcoder
4
¿Hay alguna forma de evitar el parpadeo?
Waltari
ustedes son los mejores muchachos
Khadam Ikhwanus
17

React Native TextInput proporciona accesorios keyboardType con los siguientes valores posibles: teclado numérico predeterminado teclado decimal numérico dirección de correo electrónico teclado numérico

para su caso, puede usar keyboardType = 'number-pad' para aceptar solo números. Esto no incluye '.'

entonces,

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

es lo que tienes que usar en tu caso.

para obtener más detalles, consulte el enlace de documento oficial para TextInput: https://facebook.github.io/react-native/docs/textinput#keyboardtype

Ganesh Krishna
fuente
10

Función para validar la 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 esto sea útil.

Abdul Karim Khan
fuente
esa es una forma más eficiente, se debe seguir en lugar del método de bucle
Asif Ali
10

Permitir solo números que utilicen una expresión regular

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

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

Es posible que desee tener más de una validación


<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
fuente
No es necesario crear estas dos primeras funciones, solo puede usar:validations(value: string) { return /0/.test(value) && /^\d+$/.test(value) ? this.setState({ numColumns: value }) : false; }
Frederiko Cesar
2
@FrederikoCesar Eche un vistazo al principio de responsabilidad única
jasonleonhard
9

Primera solucion

Puede utilizar 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>

En el primer caso se incluyen signos de puntuación ej: - . y -

Segunda solución

Utilice expresiones regulares para eliminar los signos de puntuación.

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

Por favor, consulte el enlace de la merienda

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

Vishal Dhanotiya
fuente
8

Un amable recordatorio para aquellos que encontraron el problema de que "onChangeText" no puede cambiar el valor de TextInput como se esperaba en iOS: eso es en realidad un error en ReactNative y se ha corregido en la versión 0.57.1. Consulte: https://github.com/facebook/react-native/issues/18874

Ala
fuente
Esto debería ser un comentario y no una respuesta
Haris Nadeem
1
Disculpe que no tengo la reputación suficiente para comentar la pregunta, así que termino con una respuesta, con suerte para llamar la atención sobre las personas que buscan soluciones viables.
Ala
Punto justo. Veo que se necesitarían 50 de reputación para comentar. Lamentablemente, no puedo eliminar esa restricción, pero puedo darte 10 de reputación y, con suerte, eliminar algunas de las restricciones.
Haris Nadeem
Tómate 10 más para obtener comentarios ... Saludos @Wing
Venkatesh Somu
Gracias :) @VenkateshSomu
Wing
4
<TextInput autoCapitalize={'none'} maxLength={10} placeholder='Mobile Number'  value={this.state.mobile} onChangeText={(mobile) => this.onChanged(mobile)}/>

y 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
fuente
Su solución, aunque resuelve mi problema, produce una advertencia: "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."no sé qué hacer con esto. ¿Puede usted ayudar?
Mike
@ Mike, algún evento podría causar esto, ¿puedes compartir el código de tu componente a través de jsfiddle o rnplay.org?
Bheru Lal Lohar
Lo resolví poco después de comentar aquí, pero desafortunadamente puedo averiguar cuál era el problema.
Mike
usar una expresión regular sería una opción más inteligente
Asif Ali
4

Tuve el mismo problema en iOS, al usar el evento onChangeText para actualizar el valor del texto escrito por el usuario, no podía actualizar el valor de TextInput, por lo que el usuario aún vería los caracteres no numéricos que escribió.

Esto se debió a que, cuando se presionaba un carácter no numérico, el estado no cambiaba ya que this.setState estaría usando el mismo número (el número que quedaba después de eliminar los caracteres no numéricos) y luego el TextInput no volvería a renderizarse.

La única forma que encontré para resolver esto fue usar el evento keyPress que ocurre antes del evento onChangeText, y en él, usar setState para cambiar el valor del estado a otro, completamente diferente, forzando la re renderización cuando se llamó al evento onChangeText . No estoy muy contento con esto, pero funcionó.

Gustavo Franco
fuente
4
if (!/^[0-9]+$/.test('123456askm')) {
  consol.log('Enter Only Number');
} else {
    consol.log('Sucess');
}
ANKIT-DETROJA
fuente
! / ^ [0-9] + $ /. Test ('123456askm') comprobará que la cadena de entrada sea numérica o no .test (Su valor)
ANKIT-DETROJA
1
Hola, amplíe su respuesta sobre por qué esto sería una solución al problema de OP. Esto ayudará a OP y a los futuros visitantes del sitio. ¡Gracias!
d_kennetz
3

Escribí esta función que encontré útil para evitar que el usuario pudiera ingresar algo más de lo que estaba dispuesto a aceptar. Yo también usé keyboardType="decimal-pad"y mionChangeText={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 })
    }
}

El primer ifbloque es el manejo de errores para el evento en el que el usuario borra todo el texto, o usa un punto decimal como primer carácter, o si intenta poner más de un lugar decimal, el segundo ifbloque se asegura de que pueda escribir como tantos números como quieran antes del lugar decimal, pero solo hasta dos lugares decimales después del punto.

Andrew M Yasso
fuente
2

Usar una expresión regular para reemplazar cualquier dígito que no sea. Tenga cuidado, el siguiente código le dará el primer dígito que encontró, por lo que si el usuario pega un párrafo con más de un número (xx.xx), el código le dará el primer número. Esto le ayudará si quiere algo como el precio, no un teléfono móvil.

Use esto para su controlador onTextChange:

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

Puede eliminar caracteres no numéricos usando expresiones regulares

onTextChanged (text) {
    this.setState({
        myNumber: text.replace(/\D/g, ''),
    });
}
Anoop
fuente
1

Esto no funciona en IOS, setState -> render -> no cambia el texto, pero puede cambiar otro. La entrada de texto no puede cambiar su valor cuando textOnChange.

por cierto, esto funciona bien en Android.

wv1124
fuente
Explique con código de ejemplo para que otros puedan entender.
Bheru Lal Lohar
1

Aquí está mi otra respuesta simple para aceptar solo números en el cuadro de texto usando expresiones regulares.

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

Para el número de coma decimal / flotante, intente esto

    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
fuente
0

Bueno, esta es una forma muy sencilla de validar un número diferente a 0.

if (+inputNum)

Será NaN si inputNum no es un número o falso si es 0

Félix Andersson
fuente