React Native: How to make a card expire using / using <TextInput / ">?
In React Native using <TextInput/>
, I try to make /
display only when <TextInput/>
focused, and will stay there if another input is entered. Currently, the format is MM/YY
, so when the user enters the third digit, he will go after /
, and if the user had to press a key, he will delete the digit before /
.
So, what would be the right approach to implementing the previously mentioned? Thank you and will answer.
I tried the following, but I get an error with a length, and this is only adding /
after entering two digits:
_changeCardExpiry(value) { if (value.indexOf('.') >= 0 || value.length > 5) { return; } if (value.length === 2 && this.state.cardExpiry.length === 1) { value += '/' } //then update state cardExpiry } ... <TextInput onChangeText={this._changeCardExpiry.bind(this)} placeholder='MM/YY' value={cardExpiry} />
In formattion, you really need 3 functions to format the actual value, secondly, to convert the formatted value back to the actual value, and the third to check whether the input you entered can still be valid or not. For example, to enter a date, input letter inputs should be ignored, but at the same time, 99 should be ignored, since this is an invalid input for a month. Therefore, for your specific case, the following structure will work for you (in this example, the inputToValue
function checks whether the input you enter is valid and sets the state accordingly):
formatFunction(cardExpiry = ""){ //expiryDate will be in the format MMYY, so don't make it smart just format according to these requirements, if the input has less than 2 character return it otherwise append `/` character between 2nd and 3rd letter of the input. if(cardExpiry.length < 2){ return cardExpiry; } else{ return cardExpiry.substr(0, 2) + "/" + (cardExpiry.substr(2) || "") } } inputToValue(inputText){ //if the input has more than 5 characters don't set the state if(inputText.length < 6){ const tokens = inputText.split("/"); // don't set the state if there is more than one "/" character in the given input if(tokens.length < 3){ const month = Number(tokens[1]); const year = Number(tokens[2]); //don't set the state if the first two letter is not a valid month if(month >= 1 && month <= 12){ let cardExpiry = month + ""; //I used lodash for padding the month and year with zero if(month > 1 || tokens.length === 2){ // user entered 2 for the month so pad it automatically or entered "1/" convert it to 01 automatically cardExpiry = _.padStart(month, 2, "0"); } //disregard changes for invalid years if(year > 1 && year <= 99){ cardExpiry += year; } this.setState({cardExpiry}); } } } } render(){ let {cardExpiry} = this.state; return <TextInput value = {this.formatFunction(cardExpiry)} onChangeText={this.inputToValue.bind(this)}/>; }
you can use this func from onChangeText;
Remember to bind the method inside the constructor;
this.fixCardText = this.fixCardText.bind(this)
fixCardText(text){ if(text.length == 2 && this.state.text == 1){ text += '/' }else if(text.length == 2 && this.state.text.length == 3){ text = text.substring(0 , text.length-1) } this.setState({text:text}) }
Your text input should be as follows:
<TextInput value = {this.state.text} onChangeText={(text)=>{this.fixCardText(text)}} />
Incomplete solution, but it solves a similar problem - masking the bluetooth addressAB
AB:C
AB:CD:EF:GH:IJ:KL
/* Usage: import { TextInput } from '../utils/input' const MaskedTextInput = withMask(TextInput) <MaskedTextInput placeholder="Printer address" value={ printerId } onChange={this.handlePrinterAddressChange} /> */ import React, { Component } from 'react' import { View } from 'react-native' export const withMask = (WrappedComponent) => class Wrapper extends Component { constructor(props) { super() this.state = { value: props.value } } onChange(event) { let value = event.nativeEvent.text const rawValue = event.nativeEvent.text.replace(/:/g, '') if (rawValue) { value = rawValue.match(/.{1,2}/g).join(':').toUpperCase() } this.setState({value}) if (this.props.onChange) { event.nativeEvent.text = value this.props.onChange(event) } } render() { return <WrappedComponent {...this.props} onChange={(event) => this.onChange(event)} value={this.state.value} /> } }