Textinput minimum length React native - react-native

Is there a way to limit the textinput between a minimum length and maximum length. Suppose I want to limit the textinput length between 5 and 15, how do I do that ?

Consider adding the following code in your component:
<TextInput onTextChange={this.onTextChange} maxLength={15} ... />
<Button onPress={this.onPress} ... >Submit</Button>
onTextChange = text => {
this.setState({text : text});
}
onPress = () => {
const {text} = this.state;
if(text.length < 5) {
console.log('Your text is less than what is required.');
}
}

You can do it using redux-form, following below steps
we.js
module.exports = {
reqMsg: 'Required',
maxLength: max => value => value && value.length > max ? `Must be ${max} characters or less` : undefined,
minValue: min => value => value && value.length < min ? `Must be at least ${min} characters` : undefined,
};
validations.js
import { reqMsg, maxLength, minValue } from './we';
module.exports = {
//Validation
required: value => value ? undefined : reqMsg,
maxLength15: maxLength(15),
minValue5: minValue(5)
};
UserCreateForm.js
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
import { Item, Input, CheckBox, ListItem, Spinner, Icon } from 'native-base';
import { required, minValue5, maxLength15} from './validations';
const renderField = ({ secureTextEntry, iconType, iconName, keyboardType, placeholder, meta: { touched, error, warning }, input: { onChange, ...restInput } }) => {
return (
<View>
<Item error={touched && !!error} rounded>
<Icon type={iconType} name={iconName} />
<Input secureTpickerStyleextEntry={JSON.parse(secureTextEntry)} keyboardType={keyboardType}
onChangeText={onChange} {...restInput} placeholder={placeholder} autoCapitalize='none'>
</Input>
{touched && !!error && <Icon name='close-circle' />}
</Item>
{touched && (!!error && <Text>{error}</Text>)}
</View>
);
};
class UserComponent extends Component {
render() {
return (
<Field name="Name" iconType="SimpleLineIcons" iconName="user" secureTextEntry="false" keyboardType="default" placeholder="FirstName LastName NikeName" component={renderField}
validate={[required, minValue5, maxLength15]}
/>
);
}
}
const UserCreateForm = reduxForm({
form: USER_CREATE_FORM // a unique identifier for this form
})(UserComponent);
export default UserCreateForm;

Previous comment is also Good, but it have more time and space complexity. For this overcome use this code .
<TextInput onTextChange={this.onTextChange} maxLength={15} ... />
onTextChange=()=>{
if (value ==^[a-zA-Z0-9]{5,15}$) {
alert( "Input is valid\n");
} else {
alert( "Input is invalid\n");
}
}
this code help me use this code, you can also reset the limit length, change the value
here 5 :- minimum
15:- maximum value.

Related

Clearing Input in React Native

I'm new to react native.
I've created a react native app and my first screen is a login screen. I'm using onChangeText to update state vars with username and password and this works great initially.
However on "logout" when I pop back to the login screen. The inputs still have my username and password in. However the state vars are now back to null.
I've tried setting value to {this.state.username} for the input but this just causes a depth error on state after 2 input presses so doesn't work.
Am I missing something?
import React, { Component } from 'react';
import { View, Text, StyleSheet, Image, Alert, AsyncStorage, Linking } from 'react-native';
import { Input, Left, Spinner, Container, Item, Form, Header, Content, Label, Button } from 'native-base'
export default class Login extends Component {
state = { username: "", password: "", isLoaded: true }
static navigationOptions = {
header: null
}
constructor(props) {
super()
this.state.isLoaded = false
AsyncStorage.getItem("loggedIn").then(res => {
if (res === "true") {
this.props.navigation.navigate('List')
}
else {
this.setState({isLoaded: true})
}
})
}
checkLogin() {
if ((!this.state.username) || (!this.state.password)) {
Alert.alert('Error', 'Username/Password combination unknown', [{
text: 'Okay'
}])
return
}
....... snip ......
if (response === false) {
Alert.alert('Error', 'Username/Password combination unknown', [{
text: 'Okay'
}])
}
else {
AsyncStorage.setItem('user', JSON.stringify(response));
AsyncStorage.setItem('loggedIn', "true");
this.setState({username: null, password: null})
this.props.navigation.navigate('List')
}
}
}
render()
{
if (this.state.isLoaded == false) {
return (
<Container>
<Spinner />
</Container>
)
}
return (
<Container>
<Content>
<Image source={require('../../assets/logo.jpg')}/>
<Form>
<Item floatingLabel>
<Label>Username</Label>
<Input
autoCapitalize='none'
clearButtonMode='always'
onChangeText={text => this.setState({username:text})} />
</Item>
<Item floatingLabel>
<Label>Password</Label>
<Input
secureTextEntry={true}
clearButtonMode='always'
onChangeText={text => this.setState({password: text})} />
</Item>
<Button primary onPress={_ => this.checkLogin()}>
<Text style={styles.loginButtonText}>Login</Text>
</Button>
</Form>
</Content>
</Container>
);
}
}
You can use direct manipulation method.
Try passing ref to Input like ref={ (c) => this._input = c } and then calling the setNativeProps function this._input.setNativeProps({text:''})
I am also using react navigation and face similar issue.
I fixed as below :
import { NavigationEvents } from "react-navigation";
class ... {
onStartScreenFocus = ()>={
this.setState({
username: "", password: ""
})
}
render(){
return(
<View>
<NavigationEvents
onWillFocus={() => this.onStartScreenFocus()}
onDidBlur={() => this.onDidScreenBlur()} />
<View>
)
}
}

DatePicker input value not pass to Redux Form when submit

I'm using DatePicker with ReduxForm. However, when I click submit button, the input value from Date Picker not pass to Redux Form.
I've search around and come across the answer from this (my code of renderDatePicker comes from there) but it still doesn't work for me.
My demo of the form on my Simulator:
Here's my code:
import React, { Component } from 'react';
import {
View, Text, Button, Icon, Container, Item,
Input, Label, Content, Form, Picker, Footer, DatePicker
} from 'native-base';
import { Field, reduxForm } from 'redux-form';
import { addTransactionItem } from '../redux/ActionCreators';
import moment from 'moment';
import { connect } from 'react-redux';
const mapDispatchToProps = dispatch => ({
addTransactionItem: (transactionItem) => dispatch(addTransactionItem(transactionItem))
})
class AddTransaction extends Component {
constructor(props) {
super(props);
this.renderField = this.renderField.bind(this);
this.submit = this.submit.bind(this);
this.renderDatePicker = this.renderDatePicker.bind(this);
}
renderDatePicker = ({ input, placeholder, defaultValue, meta: { touched, error }, label ,...custom }) => (
<Item>
<Label>{label}</Label>
<DatePicker {...input} {...custom} dateForm="MM/DD/YYYY"
onChange={(value) => input.onChange(value)}
autoOk={true}
selected={input.value ? moment(input.value) : null} />
{touched && error && <span>{error}</span>}
</Item>
);
submit = values => {
alert(`The values are ${JSON.stringify(values)}`)
const transactionItem = JSON.parse(JSON.stringify(values))
this.props.addTransactionItem(transactionItem);
const { navigate } = this.props.navigation;
navigate('Home');
}
render() {
const { handleSubmit } = this.props
return (
<>
<Form>
<Field keyboardType='default' label='Date' component={this.renderDatePicker} name="date" />
</Form>
<Button full light onPress={handleSubmit(this.submit)}>
<Text>Submit</Text>
</Button>
</>
);
}
}
AddTransaction = connect(null, mapDispatchToProps)(AddTransaction);
export default reduxForm({
form: 'addTransaction',
})(AddTransaction);
I think this is because you do not have "change" attribute in the Field component.
Try to add change function as shown below:
renderDatePicker = (
{
input,
placeholder,
defaultValue,
meta: { touched, error },
label ,
...custom,
change
}
) => (
<Item>
<Label>{label}</Label>
<DatePicker {...input} {...custom} dateForm="MM/DD/YYYY"
onDateChange={change}
autoOk={true}
selected={input.value ? moment(input.value) : null} />
{touched && error && <span>{error}</span>}
</Item>
);
render() {
const { handleSubmit, change } = this.props
return (
<>
<Form>
<Field
keyboardType='default'
label='Date'
component={this.renderDatePicker}
name="date"
change={change}
/>
</Form>
<Button full light onPress={handleSubmit(this.submit)}>
<Text>Submit</Text>
</Button>
</>
);
}
Hope it will work for you.
I see that there is no onChange listener for DatePicker. May be you should use onDateChange. http://docs.nativebase.io/Components.html#picker-input-headref

React Native Form Validation

I created a login form using react-native and I want to validate every fields but I don't know how to do it. I'm quite new to react-native so I want to ask anyone for help. Form validation should show error under following conditions:
Input form is empty
Email text isn't email form.
Password text does not satisfy the conditions above.
If Input form has errors the login button should be disabled.
If Input form doesn't have any errors, show alert to inform login
success
Sample image validation:
Here is my code:
import React from 'react';
import { StyleSheet, Text, View, Image, TextInput, Dimensions, ScrollView,
CheckBox, TouchableOpacity } from 'react-native';
import logo from './image/Logo.png'
const { width: WIDTH } = Dimensions.get('window')
export default class App extends React.Component {
constructor(){
super();
this.state={
check:false,
email: '',
};
this.validates = this.validates.bind(this);
}
CheckBoxText(){
this.setState({
check:!this.state.check,
})
}
validates = () => {
let text = this.state.email;
let emailError = this.state.emails;
let reg = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/ ;
if(reg.test(text) === false)
{
console.warn("Invalid email")
this.setState({email:text})
return false;
}
else {
this.setState({email:text})
console.log("Email is Correct");
}
}
render() {
return (
<View>
<View style={styles.container}>
<Image source={logo} style={styles.logo}/>
</View>
<View style = {styles.container2}>
<Text style={styles.emailAdd}>
Email
</Text>
<TextInput
onChangeText={(text) => this.setState({email:text})}
type='email'
value={this.state.email}
keyboardType='email-address'
style={styles.emailInput}
placeholder={'Input Email Address'}
underlineColorAndroid='transparent'/>
</View>
<View style = {styles.container3}>
<Text style={styles.password}>
Password
</Text>
<TextInput
style={styles.passwordInput}
placeholder={'Input Password'}
secureTextEntry={true}
underlineColorAndroid='transparent'/>
</View>
<View style = {styles.container4}>
<View>
<CheckBox value={this.state.check} onChange={()=>this.CheckBoxText()} style={styles.rememberMe}/>
</View>
<View>
<Text style={styles.remember}>Remember me</Text>
</View>
</View>
<TouchableOpacity style={styles.btnLogin} onPress={this.validates} >
<Text style={styles.txtLogin}>Sign In</Text>
</TouchableOpacity>
</View>
);
}
}
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
var validRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+#[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
if (!email) {
Toast.show('Email is required.');
} else if (!email.match(validRegex)) {
Toast.show('Invalid Email');
} else if (!password) {
Toast.show('Password is required.');
}
I recommend using formik and yup to easily build a login form with input validation. These two packages when integrated together, simplifies your codebase thanks to both of its features.
Please take a look at a CodeSandbox snippet here, https://codesandbox.io/s/stack-overflow-54204827-llvkzc?file=/index.tsx:254-656. And note, I'm using typescript here.
The package.json file at the time of written snippet is:
"dependencies": {
...
"formik": "2.2.9",
...
"yup": "0.32.11"
},
And to break the solution down, first we define our yup schema for our Login form:
Note, you may tweak the regex pattern later, as this password validation accepts min 6 to max 12 characters, with at least one uppercase letter, one lowercase letter, one number and one special character.
/**
* The `yup` Login Form schema
*/
const LoginSchemaA = Yup.object().shape({
email: Yup.string()
.email("Invalid email.")
.required("Email must be provided."),
password: Yup.string()
.required("Password must be provided.")
.matches(
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!##\$%\^&\*])(?=.{6,12})/,
"Password must be minimum 6 and maximum 12 characters."
)
});
Note, .email("Invalid email.") here is the default email validation feature used. You can remove this, and use .matches(...) function instead for your own regular expression.
And just the <Formik /> section for your further use:
<Formik
initialValues={{
email: "",
password: ""
}}
validationSchema={LoginSchemaA}
onSubmit={(
values: Values,
{ setSubmitting }: FormikHelpers<Values>
) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 500);
}}
>
{({ errors, touched }) => (
<Form>
<label htmlFor="email">Email</label>
<Field
id="email"
name="email"
placeholder="john.doe#email.com"
type="email"
/>
{errors.email && touched.email ? (
<div style={{ color: "red" }}>{errors.email}</div>
) : null}
<label htmlFor="password">Password</label>
<Field id="password" name="password" type="password" />
{errors.password && touched.password ? (
<div style={{ color: "red" }}>{errors.password}</div>
) : null}
<button type="submit">Submit</button>
</Form>
)}
</Formik>
Lastly, you would want to grab the values itself for further use - ignore the setTimeout, alert and setSubmitting usages.
An example output of JSON.stringify(values, null, 2) would be as below:
{
"email": "john.doe#test.com",
"password": "Awesome#Password!2022"
}
Hope this helps you in your react-native coding journey!
here is my code you can try this
import React, { Component } from "react"
import { View, Button } from "react-native"
import TextField from "textfield"
import validation from "validation"
import validate from "validation_wrapper"
export default class Form extends Component {
constructor(props) {
super(props)
this.state = {
email: "",
emailError: "",
password: "",
passwordError: ""
}
}
register() {
const emailError = validate("email", this.state.email)
const passwordError = validate("password", this.state.password)
this.setState({
emailError: emailError,
passwordError: passwordError
})
if (!emailError && !passwordError) {
alert("Details are valid!")
}
}
render() {
return (
<View>
<TextField
onChangeText={(value) => this.setState({ email: value.trim() })}
onBlur={() => {
this.setState({
emailError: validate("email", this.state.email)
})
}}
error={this.state.emailError}
/>
<TextField
onChangeText={(value) => this.setState({ password: value.trim() })}
onBlur={() => {
this.setState({
passwordError: validate("password", this.state.password)
})
}}
error={this.state.passwordError}
secureTextEntry={true}
/>
<Button title="Register" onPress={this.validateRegister} />
</View>
)
}
}
<!-- begin snippet: js hide: false console: true babel: false -->
const validation = {
email: {
presence: {
message: "^Please enter an email address"
},
email: {
message: "^Please enter a valid email address"
}
},
password: {
presence: {
message: "^Please enter a password"
},
length: {
minimum: 5,
message: "^Your password must be at least 5 characters"
}
}
}
export default validation
import validation from "validation.js"
export default function validate(fieldName, value) {
// Validate.js validates your values as an object
// e.g. var form = {email: 'email#example.com'}
// Line 8-9 creates an object based on the field name and field value
var formValues = {}
formValues[fieldName] = value
// Line 13-14 creates an temporary form with the validation fields
// e.g. var formFields = {
// email: {
// presence: {
// message: 'Email is blank'
// }
// }
var formFields = {}
formFields[fieldName] = validation[field]
// The formValues and validated against the formFields
// the variable result hold the error messages of the field
const result = validatejs(formValues, formFields)
// If there is an error message, return it!
if (result) {
// Return only the field error message if there are multiple
return result[field][0]
}
return null
}
import React from "react"
import { View, TextInput, Text } from "react-native"
const TextField = (props) => (
<View>
<TextInput />
props.error ? <Text>{props.error}</Text> : null
</View>
)
export default TextField

Focus not changing from TextInput in redux-form

I have form with only one TextInput which is made using redux-form. I am checking (!meta.active) to show validation message, since focus is not changing even on button click from TextInput, meta.active is always true and validation message does not shows up.
export default function MTTextInput(props) {
const { input, label, meta, ...inputProps } = props;
var hasError = false;
if (meta.error !== undefined && meta.touched && !meta.active) {
hasError = true;
}
return (
<Item fixedLabel error={hasError} ><Label>{label}</Label>
<Input
{...inputProps}
onChangeText={input.onChange}
onBlur={input.onBlur}
onFocus={input.onFocus}
value={input.value}
/>
{hasError ? <Text>{meta.error}</Text> : <Text />}
</Item>
);
}
MTTextInput.propTypes = {
input: PropTypes.shape({
onBlur: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func.isRequired,
value: PropTypes.any.isRequired
}).isRequired,
meta: PropTypes.shape({
active: PropTypes.bool.isRequired,
error: PropTypes.string,
invalid: PropTypes.bool.isRequired,
pristine: PropTypes.bool.isRequired,
visited: PropTypes.bool.isRequired
}).isRequired
};
Perhaps you may want to switch from an <Input/> component to a <TextInput/> component. Here is a generic example that you can find here:
import React from 'react';
import { TextInput, View, Text } from 'react-native';
/**
* to be wrapped with redux-form Field component
*/
export default function MyTextInput(props) {
const { input, meta, ...inputProps } = props;
const formStates = ['active', 'autofilled', 'asyncValidating', 'dirty', 'invalid', 'pristine',
'submitting', 'touched', 'valid', 'visited'];
return (
<View>
<TextInput
{...inputProps}
onChangeText={input.onChange}
onBlur={input.onBlur}
onFocus={input.onFocus}
value={input.value}
/>
<Text>The { input.name} input is:</Text>
{
formStates.filter((state) => meta[state]).map((state) => {
return <Text key={state}> - { state }</Text>;
})
}
</View>
);
}

React native redux form initial values not showing

This is my code for redux form. I have also set enableReinitialize to true and followed the react-form documentation.
I have hard coded the initialValues object just for testing purposes. But still my form is not getting initialized.
import React, { Component } from 'react';
import { Container, Header, Body, Content, Title, Button, Text, Left, Icon, Right } from 'native-base';
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import MyTextInput from './TextInput';
import { fetchProfileData } from '../../actions';
const validate = values => {
const error = {};
error.email = '';
error.name = '';
error.mobile = '';
let ema = values.email;
let nm = values.name;
let mob = values.mobile;
if (values.email === undefined) {
ema = '';
}
if (values.name === undefined) {
nm = '';
}
if (values.mobile === undefined) {
mob = '';
}
if (ema.length < 8 && ema !== '') {
error.email = 'too short';
}
if (!ema.includes('#') && ema !== '') {
error.email = '# not included';
}
if (nm.length > 8) {
error.name = 'max 8 characters';
}
if (mob.length < 10 && mob !== '') {
error.mobile = 'min 10 digits';
}
return error;
};
class SimpleForm extends Component {
componentWillMount() {
this.props.fetchProfileData();
}
render() {
const { handleSubmit } = this.props;
console.log(this.props.initialValues);
return (
<Container>
<Header>
<Left>
<Button
transparent
onPress={() => this.props.navigation.navigate('DrawerOpen')}
>
<Icon name="menu" />
</Button>
</Left>
<Body>
<Title>Profile</Title>
</Body>
<Right />
</Header>
<Content padder>
<Field name='name' component={MyTextInput} label='Vendor Name' />
<Field name='company_name' component={MyTextInput} label='Company Name' />
<Field name='office_address' component={MyTextInput} label='Office Address' />
<Field name='email' component={MyTextInput} label='Email' />
<Field name='mobile' component={MyTextInput} label='Contact' />
<Button block primary onPress={handleSubmit((values) => console.log(values))} style={{ marginTop: 20 }}>
<Text>Save</Text>
</Button>
</Content>
</Container>
);
}
}
const mapStateToProps = state => {
return {
initialValues: { name: 'abcde#gmail.com' }
};
};
SimpleForm = connect(mapStateToProps, { fetchProfileData }
)(SimpleForm);
export default reduxForm({
form: 'test',
validate,
enableReinitialize: true
})(SimpleForm);
I've been struggling with this for some time. I've never been able to get anything with props to work. But I just need to some initial state stuff, so this works for me. Hope it works for you as well.
----- This works if you only want to set the initial values once.
export default reduxForm({
form: 'test',
validate,
initialValues: { name: 'abcde#gmail.com' }
})(SimpleForm);
Edit: It seemed I needed to pass variables in. This has been able to work for me for variables set in mapStateToProps. I think your setup didn't work because it is mapping state and props to the form, then adding reduxForm. It looks like it needs to be the other way around.
const mapStateToProps = (state) => {
return {
initialValues: {
name: 'foobar',
}
}
}
export default (connect(mapStateToProps, mapDispatchToProps)(reduxForm({
form: 'groupForm',
enableReinitialize: true
})(SimpleForm)))