I am stuck with a very simple problem. I have login form with username, password and button. In my button handler, I try to get the textinput value. But always get undefined value. Am I missing something?
render() {
<ExScreen
headerColor={this.state.headerColor}
scrollEnabled={this.state.enableScroll}
style={styles.container} >
<View >
<View >
<View style={[styles.inputContainer]} >
<TextInput
ref= "username"
onChangeText={(text) => this.setState({text})}
value={this.state.username}
/>
</View>
<Button style={{color: 'white', marginTop: 30, borderWidth: 1, borderColor: 'white', marginLeft: 20*vw, marginRight: 20*vw, height: 40, padding: 10}}
onPress={this._handlePress.bind(this)}>
Sign In
</Button>
...
_handlePress(event) {
var username=this.refs.username.value;
The quick and less optimized way to do this is by using arrow function inside your onChangeText callback, by passing username as your argument in your onChangeText callback.
<TextInput
ref= {(el) => { this.username = el; }}
onChangeText={(username) => this.setState({username})}
value={this.state.username}
/>
then in your _handlePress method
_handlePress(event) {
let username=this.state.username;
}
But this has several drawbacks!!!
On every render of this component a new arrow function is created.
If the child component is a PureComponent it will force re-renders unnecessarily, this causes huge performance issue especially when dealing with large lists, table, or component iterated over large numbers. More on this in React Docs
Best practice is to use a handler like handleInputChange and bind ```this`` in the constructor.
...
constructor(props) {
super(props);
this.handleChange= this.handleChange.bind(this);
}
...
handleChange(event = {}) {
const name = event.target && event.target.name;
const value = event.target && event.target.value;
this.setState([name]: value);
}
...
render() {
...
<TextInput
name="username"
onChangeText={this.handleChange}
value={this.state.username}
/>
...
}
...
Or if you are using es6 class property shorthand which autobinds this. But this has drawbacks, when it comes to testing and performance. Read More Here
...
handleChange= (event = {}) => {
const name = event.target && event.target.name;
const value = event.target && event.target.value;
this.setState([name]: value);
}
...
render() {
...
<TextInput
name="username"
onChangeText={this.handleChange}
value={this.state.username}
/>
...
}
...
You should use States to store the value of input fields.
https://facebook.github.io/react-native/docs/state.html
To update state values use setState
onChangeText={(value) => this.setState({username: value})}
and get input value like this
this.state.username
Sample code
export default class Login extends Component {
state = {
username: 'demo',
password: 'demo'
};
<Text style={Style.label}>User Name</Text>
<TextInput
style={Style.input}
placeholder="UserName"
onChangeText={(value) => this.setState({username: value})}
value={this.state.username}
/>
<Text style={Style.label}>Password</Text>
<TextInput
style={Style.input}
placeholder="Password"
onChangeText={(value) => this.setState({password: value})}
value={this.state.password}
/>
<Button
title="LOGIN"
onPress={() =>
{
if(this.state.username.localeCompare('demo')!=0){
ToastAndroid.show('Invalid UserName',ToastAndroid.SHORT);
return;
}
if(this.state.password.localeCompare('demo')!=0){
ToastAndroid.show('Invalid Password',ToastAndroid.SHORT);
return;
}
//Handle LOGIN
}
}
/>
In React Native 0.43: (Maybe later than 0.43 is OK.)
_handlePress(event) {
var username= this.refs.username._lastNativeText;
If you are like me and doesn't want to use or pollute state for one-off components here's what I did:
import React from "react";
import { Text, TextInput } from "react-native";
export default class Registration extends Component {
_register = () => {
const payload = {
firstName: this.firstName,
/* other values */
}
console.log(payload)
}
render() {
return (
<RegisterLayout>
<Text style={styles.welcome}>
Register
</Text>
<TextInput
placeholder="First Name"
onChangeText={(text) => this.firstName = text} />
{/*More components...*/}
<CustomButton
backgroundColor="steelblue"
handlePress={this._register}>
Submit
</CustomButton>
</RegisterLayout>
)
}
}
export default class App extends Component {
state = { username: '', password: '' }
onChangeText = (key, val) => {
this.setState({ [key]: val})
}
render() {
return (
<View style={styles.container}>
<Text>Login Form</Text>
<TextInput
placeholder='Username'
onChangeText={val => this.onChangeText('username', val)}
style={styles.input}
/>
<TextInput
placeholder='Password'
onChangeText={val => this.onChangeText('password', val)}
style={styles.input}
secureTextEntry={true}
/>
</View>
);
}
}
Hope this will solve your problem
This work for me
<Form>
<TextInput
style={{height: 40}}
placeholder="userName"
onChangeText={(text) => this.userName = text}
/>
<TextInput
style={{height: 40}}
placeholder="Password"
onChangeText={(text) => this.Password = text}
/>
<Button
title="Sign in!"
onPress={this._signInAsync}
/>
</Form>
and
_signInAsync = async () => {
console.log(this.userName)
console.log(this.Password)
};
Please take care on how to use setState(). The correct form is
this.setState({
Key: Value,
});
And so I would do it as follows:
onChangeText={(event) => this.setState({username:event.nativeEvent.text})}
...
var username=this.state.username;
Try Console log the object and you will find your entered text inside nativeEvent.text
example:
handelOnChange = (enteredText) => {
console.log(enteredText.nativeEvent.text)
}
render()
return (
<SafeAreaView>
<TextInput
onChange={this.handelOnChange}
>
</SafeAreaView>
)
constructor(props) {
super(props);
this.state ={
commentMsg: ''
}
}
onPress = () => {
alert("Hi " +this.state.commentMsg)
}
<View style={styles.sendCommentContainer}>
<TextInput
style={styles.textInput}
multiline={true}
onChangeText={(text) => this.setState({commentMsg: text})}
placeholder ='Comment'/>
<Button onPress={this.onPress}
title="OK!"
color="#841584"
/>
</TouchableOpacity>
</View>
Simply do it.
this.state={f_name:""};
textChangeHandler = async (key, val) => {
await this.setState({ [key]: val });
}
<Textfield onChangeText={val => this.textChangeHandler('f_name', val)}>
Every thing is OK for me by this procedure:
<Input onChangeText={this.inputOnChangeText} />
and also:
inputOnChangeText = (e) => {
this.setState({
username: e
})
}
React Native Latest -> Simple and easy solution using state based approach.
const [userEmail, setUserEmail] = useState("");
<TextInput
value={userEmail}
style={styles.textInputStyle}
placeholder="Email"
placeholderTextColor="steelblue"
onChangeText={(userEmail) => setUserEmail(userEmail)}
/>
If you set the text state, why not use that directly?
_handlePress(event) {
var username=this.state.text;
Of course the variable naming could be more descriptive than 'text' but your call.
There is huge difference between onChange and onTextChange prop of <TextInput />. Don't be like me and use onTextChange which returns string and don't use onChange which returns full objects.
I feel dumb for spending like 1 hour figuring out where is my value.
You dont need to make a new function for taht.
just make a new useState and use it in onchange.
const UselessTextInput = () => {
const [text, onChangeText] = React.useState("Useless Text");
const [number, onChangeNumber] = React.useState(null);
return (
<SafeAreaView>
<TextInput
style={styles.input}
onChangeText={onChangeText}
value={text}
/>
<TextInput
style={styles.input}
onChangeText={onChangeNumber}
value={number}
placeholder="useless placeholder"
keyboardType="numeric"
/>
</SafeAreaView>
);
};
This piece of code worked for me. What I was missing was I was not passing 'this' in button action:
onPress={this._handlePress.bind(this)}>
--------------
_handlePress(event) {
console.log('Pressed!');
var username = this.state.username;
var password = this.state.password;
console.log(username);
console.log(password);
}
render() {
return (
<View style={styles.container}>
<TextInput
ref="usr"
style={{height: 40, borderColor: 'gray', borderWidth: 1 , marginTop: 10 , padding : 10 , marginLeft : 5 , marginRight : 5 }}
placeHolder= "Enter username "
placeholderTextColor = '#a52a2a'
returnKeyType = {"next"}
autoFocus = {true}
autoCapitalize = "none"
autoCorrect = {false}
clearButtonMode = 'while-editing'
onChangeText={(text) => {
this.setState({username:text});
}}
onSubmitEditing={(event) => {
this.refs.psw.focus();
}}
/>
<TextInput
ref="psw"
style={{height: 40, borderColor: 'gray', borderWidth: 1 , marginTop: 10,marginLeft : 5 , marginRight : 5}}
placeholder= "Enter password"
placeholderTextColor = '#a52a2a'
autoCapitalize = "none"
autoCorrect = {false}
returnKeyType = {'done'}
secureTextEntry = {true}
clearButtonMode = 'while-editing'
onChangeText={(text) => {
this.setState({password:text});
}}
/>
<Button
style={{borderWidth: 1, borderColor: 'blue'}}
onPress={this._handlePress.bind(this)}>
Login
</Button>
</View>
);``
}
}
User in the init of class:
constructor() {
super()
this.state = {
email: ''
}
}
Then in some function:
handleSome = () => {
console.log(this.state.email)
};
And in the input:
<TextInput onChangeText={(email) => this.setState({email})}/>
Did you try
var username=this.state.username;
Related
I want to save the values from all input fields to getdata(), but I am getting undefined value
export default function Signupfor(props) {
// const phoneInput = useRef < PhoneInput > null;
const [text, setTextname] = useState();
function getdata() {
console.log('dsd');
console.log(text);
}
const {userInfo, log} = props?.route?.params;
console.log(log.name);
return (
<View style={styles.prheight}>
<View style={styles.form}>
<Text style={styles.r}>One Last Step</Text>
<TextInput
style={styles.forminput}
label="Name"
value={userInfo.user.name}
onChangeText={text => setTextname(text)}
/>
<TextInput
style={styles.forminput}
label="Email"
value={userInfo.user.email}
onChangeText={text => setTextemail(text)}
/>
<TextInput
style={styles.forminput}
label="Whatsapp Number"
keyboardType="numeric"
value={userInfo.user.number}
onChangeText={text => setTextnumber(text)}
// value={this.state.myNumber}
maxLength={10} //setting limit of input
/>
</View>
<View style={styles.buttonw}>
<Button color="#7743DB" title="Lets Go" onPress={() => getdata()} />
</View>
</View>
);
}
Here, name and email should not be able to be edited. I want to pass the value from value={userInfo.user.name} to the getdata()
you can use formik package for making form in react native
Installation
yarn add formik
Usage
import { Formik } from "formik";
export default function Signupfor(props) {
const { userInfo, log } = props?.route?.params;
console.log(log.name);
return (
<Formik
initialValues={{
name: userInfo.user.name,
email: userInfo.user.email,
number: userInfo.user.number,
}}
onSubmit={async (values, actions) => {
try {
console.log("name", values.name);
console.log("phone", values.number);
const params = {
full_name: values.name,
email: values.email,
phone_number: values.number,
};
} catch (error) {
let message = error.message;
console.log(message)
} finally {
actions.setSubmitting(false);
}
}}
>
{({
handleChange,
setFieldValue,
handleSubmit,
values,
errors,
touched,
isSubmitting,
}) => (
<View style={styles.prheight}>
<View style={styles.form}>
<Text style={styles.r}>One Last Step</Text>
<TextInput
style={styles.forminput}
label="Name"
value={values.name}
onChangeText={handleChange("name")}
/>
<TextInput
style={styles.forminput}
label="Email"
value={values.email}
onChangeText={handleChange("email")}
/>
<TextInput
style={styles.forminput}
label="Whatsapp Number"
keyboardType="numeric"
value={values.number}
onChangeText={handleChange("number")}
// value={this.state.myNumber}
maxLength={10} //setting limit of input
/>
</View>
<View style={styles.buttonw}>
<Button
color="#7743DB"
title="Lets Go"
onPress={() => handleSubmit()}
/>
</View>
</View>
)}
</Formik>
);
}
Your original method doesn't populate the state unless you edit the text input field, this is because your initialState doesn't have a value to start with. so firing getData() is reading empty state if the fields havent been changed.
onChangeText={text => setTextname(text)}
Only fire if you edit the textInput field.
Also I think you might be missing props, so first check if you are getting the correct data from props by logging it.
Once you have confirmed the props are available.
Set the initialState for name to userInfo.user.name
const { userInfo } = props?.route?.params;
const [name, setName] = useState(userInfo.user.name);
Then pass the state name to your TextInput and it should populate the value by reading from state.
return (
<>
<TextInput
placeholder="name"
value={name}
onChangeText={(text) => setName(text)}
/>
<Button title="Submit" onPress={() => getData()} />
</>
)
Make sure to create states for any additional values you wish to save.
const [name, setName] = useState(userInfo.user.name);
const [email, setEmail] = useState(userInfo.user.email);
You can use a library like https://react-hook-form.com to check an example with react native on video.
Or you can right it yourself, in the example below any time you need access to input values you can read it from text and number
const UselessTextInput = () => {
const [text, onChangeText] = useState("Useless Text");
const [number, onChangeNumber] = useState(null);
return (
<SafeAreaView>
<TextInput
style={styles.input}
onChangeText={onChangeText}
value={text}
/>
<TextInput
style={styles.input}
onChangeText={onChangeNumber}
value={number}
placeholder="useless placeholder"
keyboardType="numeric"
/>
</SafeAreaView>
);
};
You can do something like this!!
export default function Signupfor(props) {
const {userInfo, log} = props?.route?.params;
const [name, setName] = useState(userInfo?.user?.name);
const [phone, setPhone] = useState(userInfo?.user?.number);
function getdata() {
console.log("name",name)
console.log("phone",phone)
}
return (
<View style={styles.prheight}>
<View style={styles.form}>
<Text style={styles.r}>One Last Step</Text>
<TextInput
style={styles.forminput}
label="Name"
// this value must be same with useState
value={name}
onChangeText={text => setName(text)}
/>
<TextInput
style={styles.forminput}
label="Mobile"
value={phone}
onChangeText={text => setPhone(text)}
/>
</View>
<View style={styles.buttonw}>
<Button color="#7743DB" title="Lets Go" onPress={() => getdata()} />
</View>
</View>
);
}
Same goes for email.
I would like to add a UnicodeText viewed inside the textInput when I click a button.
I've tried to create a state {text} then add the UnicodeText to the state text.
The text with the added text is properly shown in the console.log(). Not in the textInput.
import { Icon, Input } from "react-native-elements";
var emoji = require("node-emoji");
export default class MainViewMessageInput extends React.Component {
constructor(props) {
super(props);
this.state = {
text: "",
username: "",
visible: false,
showEmoticons: false
};
}
_sendMessage() {
var texte = this.state.text;
this.setState({ text: "" });
console.log(this.state.text);
}
_addEmoji() {
this.state.text = this.state.text + emoji.get("green_heart");
const emojiChar = this.state.text + emoji.get("green_heart");
this.setState({ text: emojiChar });
console.log(this.state.text);
}
render() {
return (
<View style={styles.container}>
<Input
style={{ flex: 1 }}
leftIcon={
<TouchableHighlight
onPress={() => {
this._addEmoji();
}}
style={styles.icon}
>
<Icon size={40} color="#d2d3d5" name="mood" />
</TouchableHighlight>
}
rightIcon={
<Icon
reverse
onPress={() => this.setState({ visible: true })}
color="#00b5ec"
name="send"
size={23}
/>
}
rightIconContainerStyle={{ marginRight: -7 }}
leftIconContainerStyle={{ marginLeft: 0 }}
inputContainerStyle={styles.inputContainer}
inputStyle={styles.input}
placeholder="Write your message ..."
underlineColorAndroid="transparent"
multiline={true}
editable={true}
onChangeText={text => this.setState({ text })}
/>
</View>
);
}
}
Is it possible to do?
you can push textinput into array in runtime so u get textinput dynamically
for input add field value={this.state.text}
reference
remove this.state.text = this.state.text + emoji.get("green_heart"); from _addEmoji()
I'm trying to drive focus to the second field in a form using custom input components. However, I can't seem to access the focus() or other methods of TextInput which I am extending in the custom class. I have seen some information on ref forwarding as well as implementing the focus() function within the class but have not been able to get either working yet.
Whenever I try to hit the "next" button on the keyboard, it says that focus is not a function. Any help or reference would be appreciated.
<View>
<CustomInput
onRef={ref => (this.child = ref)}
autoCapitalize={'none'}
returnKeyType={'next'}
autoCorrect={false}
onSubmitEditing={() => this.lastNameInput.focus()}
updateState={(firstName) => this.setState({firstName})}
blurOnSubmit={false}
/>
<CustomInput
onRef={ref => (this.child = ref)}
autoCapitalize={'none'}
returnKeyType={'done'}
autoCorrect={false}
updateState={(lastName) => this.setState({lastName})}
ref={(input) => { this.lastNameInput = input; }}
onSubmitEditing={(lastName) => this.setState({lastName})}
/>
</View>
export default class UserInput extends Component {
render() {
return (
<View style={styles.inputWrapper}>
<TextInput
style={styles.input}
autoCorrect={this.props.autoCorrect}
autoCapitalize={this.props.autoCapitalize}
returnKeyType={this.props.returnKeyType}
placeholderTextColor="white"
underlineColorAndroid="transparent"
onChangeText={(value) => this.props.updateState(value)}
blurOnSubmit={this.props.blurOnSubmit}
/>
</View>
);
}
}
you need to do some changes in both components. according to https://stackoverflow.com/a/49810837/2083099
import React, { Component } from 'react'
import {View,TextInput} from 'react-native';
class UserInput extends Component {
componentDidMount() {
if (this.props.onRef != null) {
this.props.onRef(this)
}
}
onSubmitEditing() {
if(this.props.onSubmitEditing){
this.props.onSubmitEditing();
}
}
focus() {
this.textInput.focus()
}
render() {
return (
<View style={{ flex: 1 }}>
<TextInput
style={{ height: 100, backgroundColor: 'pink' }}
autoCorrect={this.props.autoCorrect}
autoCapitalize={this.props.autoCapitalize}
returnKeyType={this.props.returnKeyType}
placeholderTextColor="white"
underlineColorAndroid="transparent"
onChangeText={(value) => this.props.updateState(value)}
blurOnSubmit={this.props.blurOnSubmit}
ref={input => this.textInput = input}
onSubmitEditing={this.onSubmitEditing.bind(this)}
/>
</View>
);
}
}
export default class OrderScreen extends Component {
constructor(props) {
super(props);
this.focusNextField = this.focusNextField.bind(this);
this.inputs = {};
}
focusNextField(id) {
this.inputs[id].focus();
}
render() {
return (
<View style={{ flex: 1 }}>
<UserInput
autoCapitalize={'none'}
returnKeyType={'next'}
autoCorrect={false}
updateState={(firstName) => this.setState({ firstName })}
blurOnSubmit={false}
onRef={(ref) => { this.inputs['projectName'] = ref; }}
onSubmitEditing={() => {this.focusNextField('projectDescription');}}
/>
<UserInput
onRef={(ref) => {this.inputs['projectDescription'] = ref}}
autoCapitalize={'none'}
returnKeyType={'done'}
autoCorrect={false}
updateState={(lastName) => this.setState({ lastName })}
/>
</View>
)
}
}
The button's onPress function is called when neither of text fields above are filled. Otherwise, I press the button and nothing happens. I've tried change the onPress to onPress={this.handleSubmit()} but then the function is called before any data is in the TextInput's and an error is thrown. I've also tried using the tcomb-form-native package, but the problem persists. What do I need to change to get the handleSubmit function to be called when the text inputs are filled?
handleSubmit = () => {
console.log('handle submit')
}
render() {
return (
<View style={styles.container}>
<TextInput
style={{height: 40}}
placeholder="Your name"
onChangeText={userName => this.setState({userName})}
/>
<TextInput
style={{height: 40}}
placeholder="other name"
onChangeText={otherName => this.setState({otherName})}
/>
<Button
title="Name"
onPress={this.handleSubmit}
/>
</View>
);
}
Have you tried using
e.preventDefault()
?
handleSubmit = (e) => {
e.preventDefault()
console.log('handle submit')
}
constructor(props){
super(props);
this.state = {
userName: '',
otherName: ''
};
}
handleSubmit = () => {
// Check if any of them is empty then do nothing
if(!this.state.otherName || !this.state.userName){return;}
console.log('handle submit');
}
render() {
return (
<View style={styles.container}>
<TextInput
style={{height: 40}}
placeholder="Your name"
onChangeText={userName => this.setState({userName})}
/>
<TextInput
style={{height: 40}}
placeholder="other name"
onChangeText={otherName => this.setState({otherName})}
/>
<Button
title="Name"
onPress={this.handleSubmit}
/>
</View>
);
}
I'm having a form in my application where I want the user to be able to go to the next TextInput by clicking the "Next" return button.
My Input component:
export default class Input extends Component {
focusNextField = (nextField) => {
console.log('NEXT FIELD:', nextField);
this.refs[nextField].focus();
}
render() {
var keyboardType = this.props.keyboardType || 'default';
var style = [styles.textInput, this.props.style];
if (this.props.hasError) style.push(styles.error);
return (
<View style={styles.textInputContainer}>
<TextInput
placeholder={this.props.placeholder}
onChangeText={this.props.onChangeText}
style={style}
blurOnSubmit={false}
ref={this.props.reference}
returnKeyType= {this.props.returnType}
onSubmitEditing={() => this.focusNextField(this.props.fieldRef)}
secureTextEntry={this.props.isPassword}
value={this.props.value}
keyboardType={keyboardType}
underlineColorAndroid="transparent" />
{this.props.hasError && this.props.errorMessage ? <Text style={{ color: 'red' }}>{this.props.errorMessage}</Text> : null}
</View>
);
}
}
And how it is used:
<Input onChangeText={(email) => this.setState({ email })} value={this.state.email} returnType={"next"} reference={'1'} fieldRef={'2'} keyboardType="email-address" />
<Text style={{ color: '#fff', marginTop: 10, }}>Password</Text>
<Input onChangeText={(password) => this.setState({ password })} value={this.state.password} returnType={"done"}
reference={'2'} fieldRef={'2'} isPassword={true} />
But I get the error:
undefined is not an object (evaluating _this.refs[nextField].focus)
Not sure if you are still trying to do this but for anyone else who has the problem, please do the following :
Add this code to your imports (anywhere in your imports)
import { findNodeHandle } from 'react-native';
import TextInputState from 'react-native/lib/TextInputState';
export function focusTextInput(node) {
try {
TextInputState.focusTextInput(findNodeHandle(node));
} catch(e) {
console.log("Couldn't focus text input: ", e.message)
}
};
Add the following lines to your constructor
this.focusNextField = this.focusNextField.bind(this);
this.inputs = {};
Add the following function to your class
focusNextField(id) {
this.inputs[id].focus();
}
Edit your TextInput as follow :
<TextInput
onSubmitEditing={() => {this.focusNextField('two');}}
ref={ input => {this.inputs['one'] = input;}}
/>
<TextInput
onSubmitEditing={() => {this.focusNextField('three');}}
ref={ input => {this.inputs['two'] = input;}}
/>
....
Here is the source of that answer
Worked in 0.45 for me.