Render handler to be called when the user hits return key - react-native

I am creating a todo list. For the TextInput I do not want to use a button and the "onPress: () =>" handler to call my function with the users given text. Instead, I would like the user to just be able to hit the return key to call my function. It doesn't seem that react-native has an "onReturnKey" handler. Any suggestions for how I should go about this?
...
class App extends Component {
constructor(props) {
super(props);
this.state = { newTodo: '' };
}
AddNewTodo(text) {
return console.log(text);
}
render() {
return (
<View>
<Header headerText="VANO" />
<Card>
<CardSection style={{ backgroundColor: '#f7f7f7' }}>
<Text style={styles.titleStyle}>
Reminders
</Text>
</CardSection>
<CardSection>
<Input
placeholder="Create Reminder"
returnKeyType='done'
onChangeText={(text) => this.setState(this.newTodo: text)}
onSubmitEditing={() => this.AddNewTodo(this.state.newTodo)}
value={this.state.newTodo}
/>
</CardSection>
...

The TextInput component has a prop for returnKeyType. You can use that in conjunction with onSubmitEditing to run a function when the return key is pressed.
Example:
constructor() {
this.state = { new_todo: '' }
}
render() {
return (
....
<TextInput
returnKeyType={"done"}
onChangeText={(text) => { this.setState(new_todo: text) }}
onSubmitEditing={() => { myFunctionToAddNewTodo(this.state.new_todo) }}
value={this.state.new_todo}/>
...
)
}

Related

Getting null instead of text

I'm trying to get the text from two text fields I have.
But when I try to log the text to the console it always prints nothing, It has the LOG tag of course, but nothing else.
This is my code:
class Login extends React.Component {
state = {
email : '',
password: '',
}
handleLogin = () => {
console.log(this.state.email);
};
render() {
return(
<View style={styles.superContainer}>
<View style={styles.formContainer}>
<AppTextInput
placeHolderText="Email#Address.com"
onChangeText={(text) => this.setState({email: text})}/>
<AppTextInput
placeHolderText="Password"
onChangeText={(text) => this.setState({password: text})}/>
</View>
<View style={styles.buttonContainer}>
<AppButton
title="LOGIN"
onPress={this.handleLogin}
/>
</View>
</View>
);
}
}
I searched for an answer, but it seems like it should work. It is written just like in other answers I saw to the same question, and it is written like that on the docs I saw.
What am I doing wrong?
As request, I added an image of the console:
EDIT: I now tried to change the 'email' in the this.state part, when logging it is showing, it seems like the TextInput won't get the text on onChangeText
Try this:
import {TextInput} from 'react-native';
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: ''
};
}
handleLogin = () => {
console.log(this.state.email);
};
render() {
return(
<View style={styles.superContainer}>
<View style={styles.formContainer}>
<TextInput
placeHolderText="Email#Address.com"
onChangeText={(email) => this.setState({email})}/>
<TextInput
placeHolderText="Password"
onChangeText={(password) => this.setState({password})}/>
</View>
<View style={styles.buttonContainer}>
<AppButton
title="LOGIN"
onPress={this.handleLogin}
/>
</View>
</View>
);
}
}
I can verify that the following code is working on Snack, I have slightly modified some elements (nothing major) and used the alert, instead of console.log. You may directly paste it onto snack to view the result.
import {TextInput} from 'react-native';
import React from 'react'
import { Text, View, Button } from 'react-native';
class Login extends React.Component {
state = {
email : '',
password: '',
}
handleLogin = () => {
alert(this.state.password + " " + this.state.email);
};
render() {
return(
<View>
<View>
<TextInput
placeHolderText="Email#Address.com"
onChangeText={(text) => this.setState({email: text})}/>
<TextInput
placeHolderText="Password"
onChangeText={(text) => this.setState({ password: text })}
/>
</View>
<View >
<Button
title="LOGIN"
onPress={this.handleLogin}
/>
</View>
</View>
);
}
}
export default Login;
Finally figured it out, the problem was that I was using a custom TextInput (aka AppTextInput) and didn't pass it the onChangeText.
Adding to AppTextInput onChangeText={this.props.onChangeText} fixed the issue.
This is the full render function of AppTextInput:
render() {
const { isFocused } = this.state;
const {onFocus, onBlur, onChangeText} = this.props;
return (
<TextInput
placeholder= {this.props.placeHolderText}
selectionColor = {COLORS.appOrange}
underlineColorAndroid={
isFocused ? COLORS.appOrange : COLORS.appGray
}
onChangeText={this.props.onChangeText}
onFocus = {this.handleFocus}
onBlur = {this.handleBlur}
style = {styles.textInput}
/>
);
}

Implement onPress on Flatlist item

I am trying to send the data of the flatlist items when clicked and set to another class.The ontouch is working but I am having the error below in the image. Also how can I send the data of api to the other class and get from another class? I have implemented as follows:
export default class FlatSpeakers extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, data: [],selectedItem: null, }
const { navigate } = this.props.navigation;
}
onPressItem = () => {
navigate('SpeakersClick')
};
componentDidMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(res => {
this.setState({
isLoading: false,
data: res.data,
})
})
}
renderItem({ item }) {
return (
<TouchableOpacity onPress={()=>this.onPressItem(item)} >
<Card>
<CardSection>
<View style={styles.thumbnailContainerStyle}>
<Image
style={styles.thumbnailStyle}
source={{ uri: item.image }}
/>
</View>
<View style={styles.headerContentStyle}>
<Text style={styles.headerTextStyle}>{item.title}</Text>
<Text>{item.artist}</Text>
</View>
</CardSection>
</Card>
</TouchableOpacity>
)
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator />
</View>
)
}
return (
<View style={styles.container}>
<FlatList
data={this.state.data}
renderItem={this.renderItem}
keyExtractor={(item, index) => index}
onPress={this.onPressItem}
/>
</View>
);
}
}
Problem in your code is, that you are calling same method from two sides - on one side you are passing arguments in it on another side you are not passing arguments. If you wan't to have both cases covered you should change you onPressFunction, to accept arguments - in your case item:
onPressItem = (item) => {
navigate('SpeakersClick')
};
try to put this.onPressItem = this.onPressItem.bind(this) on constructor(props)

Passing multiple data through to next scene

I'm lost as to how to send through multiple input of data through to the next scene in my app. I have no problem with sending through one input of data "text1".
This is my sample code below.
import { Actions } from 'react-native-router-flux';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
text1: '',
text2: '',
};
}
render() {
return (
<View>
<TextInput
style={styles.input}
underlineColorAndroid="transparent"
onChangeText={text1 => this.setState({ text1 })}
/>
</View>
<View style={styles.inputContainer}>
<TextInput
style={styles.input}
underlineColorAndroid="transparent"
onChangeText={text2 => this.setState({ text2 })}
/>
</View>
<TouchableOpacity
style={styles.btnNext}
onPress={this.onPressNext.bind(this)}>
<Text style={styles.btnText}>Next</Text>
</TouchableOpacity>
);
}
Below is where i think needs fixing because the + sign isn't allowing to pass two states?
onPressNext() {
Actions.scene2({text1: this.state.text1} +
{text2: this.state.text2});
}
}
Instead of trying to pass 2 different objects, just pass it like:
Actions.scene2({text1: this.state.text1,
text2: this.state.text2})

When text input is filled, button doesn't submit

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

react native get TextInput value

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;