Passing text as param in textinput react native - javascript

<TextInput
ref={(ref) => (this.qty = ref)}
style={DefaultStyles.SeedFundSummaryTextInput}
keyboardType='numeric'
disabled={this.props.navigation.state.params.edit == false}
theme={{ colors: { text: 'rgba(0, 0, 0, .5)' } }}
// value={item.qty <= item.allowed_bags&&this.state.enable_pc_limit_check==1?
item.qty.toString() : ''}
value={ item.qty}
onBlur={ (text) => this.handleOnBlur(text) }
maxLength={5}
onChangeText={(text) => { /*item.qty = text;*/ this.handleBags(text, item)}} />
async handleOnBlur(text){
console.log(text,'onBlur')
}
Here is my code, i want to get the text in Onblur function as i get in onchangetext. What should i do?

The event is passed as param to onBlur callback, which you can get text from via nativeEvent prop:
<TextInput onBlur={e => console.log('text', e.nativeEvent.text)}/>
You can find more info here

Related

TextInput clear text on icon press not clearing

I want to set the value of my custom TextInput to "" when the iconPress is called.
The problem is, that when i call the iconPress, it should clear the text of my TextInputCode field.
But it isnt updated on my screen, isnt clearing the input field.
But it just doesnt change the value/clear it...
This is my code:
const [searchString, setSearchString] = useState("");
const submitHandler = () => {
setSearchString("")}
const changeHandler = (value) => {
setSearchString(value)}
return(...
<TextInputCode
value={searchString}
onChange={(text) => {
changeHandler(text);}}
iconType={
Platform.OS === "android"
? isSearchbarFocused
? "chevron-left"
: "search"
: "search"
}
iconPress={() => {
Platform.OS === "android" && isSearchbarFocused
? (submitHandler(), setSearchbarFocused(false), Keyboard.dismiss())
: "keine suche";
}}
showCancel
placeholderTextColor={colors.text}
onFocus={() => {
setSearchbarFocused(true);
}}
/>
...)
This is the code of my TextInputCode element, but I dont think that this is the problem:
const TextInputCode = ({
iconType,
placeholder,
onChange,
onFocus,
textContentType,
autoCapitalize,
autoCompleteType,
iconPress,
onClear
}) => {
return (
<View style={styles.inputView}>
<Icon name={iconType} onPress={iconPress} size={20}
/>
<TextInput
style={{
flex: 1,
paddingHorizontal: 12,
}}
placeholder={placeholder}
textContentType={textContentType}
autoCapitalize={autoCapitalize}
autoCompleteType={autoCompleteType}
autoCorrect={false}
onChangeText={(e) => onChange(e)}
onFocus={onFocus}
onClear = {onClear}
/>
</View>
);
};
I dont understand why this isnt working. What am I doing wrong?

how can i get the value of this inputs in react native?

so i cannot manage to get the value of any of my inputs, and the only thing is working for me is grabbing them inside render but just getting letter by letter. I want to use the same state for all of them (formData) so when I submit I can grab all the values in an unique object
Any recommendation to solve it??
export default class TimeOff extends Component {
constructor(props) {
super(props);
this.state = {
selectedStartDate: null,
selectedEndDate: null,
selectedValue: '',
formData: '',
};
}
handleSubmit = event => {
event.preventDefault()
console.log(this.state.formData)
render(){
Moment.locale('en')
const { selectedStartDate, selectedEndDate, formData, selectedValue } = this.state;
const minDate = new Date();
const maxDate = new Date(2090, 1, 1);
const startDate = selectedStartDate ? selectedStartDate.toString() : '';
const endDate = selectedEndDate ? selectedEndDate.toString() : '';
return(
<ScrollView showsVerticalScrollIndicator={false}>
<Navbar />
<Text style={styles.hOneTimeOff}>Schedule time off</Text>
<View style={styles.timeOffWrapper}>
<TextInput
name="firstname"
style={styles.timeOffInput}
mode='outlined'
placeholder="First name"
value={formData.firstname}
onChangeText={firstname => this.setState({formData: firstname})}
/>
<TextInput
name="lastname"
style={styles.timeOffInput}
mode='outlined'
placeholder="Last name"
value={formData.lastname}
onChangeText={lastname => this.setState({formData: lastname})}
/>
<Picker
name="role"
style={styles.timeOffPicker}
value={formData.role}
selectedValue={selectedValue}
onValueChange={role => this.handlePicker(role)}
>
<Picker.Item label="What's your role?" value=''/>
<Picker.Item label='Warehouse' value='Warehouse'/>
<Picker.Item label='Bakery' value='Bakery'/>
<Picker.Item label='Dry pack' value='Dry pack'/>
<Picker.Item label='Dry mix' value='Dry mix'/>
<Picker.Item label='Maintenance' value='Maintenance'/>
<Picker.Item label='Mechanical' value='Mechanical'/>
</Picker>
<View style={styles.container}>
<CalendarPicker
startFromMonday={true}
allowRangeSelection={true}
minDate={minDate}
maxDate={maxDate}
selectedDayColor="#00486D"
selectedDayTextColor="#FFFFFF"
/>
<View>
<Text>Start Date: {Moment(startDate).format("M/D/YYYY")}</Text>
<Text>End Date: {Moment(endDate).format("M/D/YYYY")}</Text>
</View>
</View>
<TouchableOpacity style={styles.btnTimeOff} onPress={this.handleSubmit}>
<Text style={styles.btnTextTimeOff}>Submit</Text>
</TouchableOpacity>
</View>
</ScrollView>
)
}
}
Your on change function is always overwriting your entire previous state.
You can use the setState function with a callback and the spread operator to update the state without losing previous state like so:
First create and function for onTextChange:
const handleChange = (name, value) => {
this.setState(
(previousState) => {
let previousFormData = previousState.formData;
return {
...previousState,
formData: {
...previousFormData,
[name]: value
}
}
}
)
}
Then Update you component like so:
export default class TimeOff extends Component {
constructor(props) {
super(props);
this.state = {
selectedStartDate: null,
selectedEndDate: null,
selectedValue: '',
formData: '',
};
}
handleSubmit = event => {
event.preventDefault()
console.log(this.state.formData)
}
handleChange = (name, value) => {
this.setState(
(previousState) => {
let previousFormData = previousState.formData;
return {
...previousState,
formData: {
...previousFormData,
[name]: value
}
}
}
)
}
render(){
Moment.locale('en')
const { selectedStartDate, selectedEndDate, formData, selectedValue } = this.state;
const minDate = new Date();
const maxDate = new Date(2090, 1, 1);
const startDate = selectedStartDate ? selectedStartDate.toString() : '';
const endDate = selectedEndDate ? selectedEndDate.toString() : '';
return(
<ScrollView showsVerticalScrollIndicator={false}>
<Navbar />
<Text style={styles.hOneTimeOff}>Schedule time off</Text>
<View style={styles.timeOffWrapper}>
<TextInput
name="firstname"
style={styles.timeOffInput}
mode='outlined'
placeholder="First name"
value={formData.firstname}
onChangeText={text => this.handleChange("firstname", text)}
/>
<TextInput
name="lastname"
style={styles.timeOffInput}
mode='outlined'
placeholder="Last name"
value={formData.lastname}
onChangeText={text => this.handleChange("lastname", text)}
/>
<Picker
name="role"
style={styles.timeOffPicker}
value={formData.role}
selectedValue={selectedValue}
onValueChange={role => this.handlePicker(role)}
>
<Picker.Item label="What's your role?" value=''/>
<Picker.Item label='Warehouse' value='Warehouse'/>
<Picker.Item label='Bakery' value='Bakery'/>
<Picker.Item label='Dry pack' value='Dry pack'/>
<Picker.Item label='Dry mix' value='Dry mix'/>
<Picker.Item label='Maintenance' value='Maintenance'/>
<Picker.Item label='Mechanical' value='Mechanical'/>
</Picker>
<View style={styles.container}>
<CalendarPicker
startFromMonday={true}
allowRangeSelection={true}
minDate={minDate}
maxDate={maxDate}
selectedDayColor="#00486D"
selectedDayTextColor="#FFFFFF"
/>
<View>
<Text>Start Date: {Moment(startDate).format("M/D/YYYY")}</Text>
<Text>End Date: {Moment(endDate).format("M/D/YYYY")}</Text>
</View>
</View>
<TouchableOpacity style={styles.btnTimeOff} onPress={this.handleSubmit}>
<Text style={styles.btnTextTimeOff}>Submit</Text>
</TouchableOpacity>
</View>
</ScrollView>
)
}
This also preserves the other variables in your state object.
You keep overwriting the "formData" state value.
Since you want it to act as an object (with entries: "firstname", "Lastname", etc) when you setState you should wrap the entries with curly brackets like this:
...
onChangeText={firstname => this.setState({formData: {firstname}})}
...
onChangeText={lastname=> this.setState({formData: {lastname}})}
...
onChangeText={firstname => this.setState({formData: {...this.state.formData, firstname}})}
onChangeText={lastname=> this.setState({formData: {...this.state.formData, lastname}})}
Use this to update the nested state object, it will keep old values and would also update new one

React-native TextInput value receiving object but I am clearly passing it a string?

state={username:"",password:""}
...
<TextInput style={styles.inputStyle}
placeholder='email123#mail.com'
autoCorrect={false}
value={this.state.username}
onChange={text =>{
this.setState({username:text});
console.log(this.state.username);
}}
/>
The error I'm getting is value is being passed an object, and it cites the line this textInput begins, but I don't see how this is possible
Styles is just:
let styles ={
titleStyle:{
fontWeight:'bold',
fontSize: 20,
textAlign:'center'
},
inputStyle:{
backgroundColor:'#d4d4d4'
}
}
Inside the render.
The onChange will return you an object, if you use onChangeText, it will return the value directly.
<TextInput
style={styles.inputStyle}
placeholder='email123#mail.com'
autoCorrect={false}
value={this.state.username}
onChangeText={text => this.setState({ username: text })}
/>
Or, if you want to use the onChange you can do it in this way:
<TextInput
style={styles.inputStyle}
placeholder='email123#mail.com'
autoCorrect={false}
value={this.state.username}
onChange={event => this.setState({ username: event.target.value })}
/>
Read React Native - Difference between onChange vs onChangeText of TextInput
Use onChangeText instead of onChange.
Try to this code:
onChange={this.onUserChange}
onUserChange = (e, {value}) => {
if (value)
this.setState({username:value})
}

React Native - Defined State not able to be use

This Screen was navigate from other Screen. When this screen is open, it will go to load some data from Webhost database and fill them into the View Controls. There are few variable is defined in the Constructor(State), but when the program trying to call the ShowAll() function (click the Show Button) to display an Alert Message with the content of a defined variable in state, the program display this error.
Error: undefined is not an object (evaluating 'this.state.RecipeName')
export default class SecondActivity extends Component
{
static navigationOptions = { title: 'View Details',};
constructor(props) {
super(props)
this.state={
RecipeID : '',
RecipeName : '',
RecipeType : '',
RecipeIngredient : '',
RecipeStep : ''
}
}
componentDidMount(){
fetch('https://unsurfaced-cross.000webhostapp.com/getRecipeDetailRN.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
// Getting the id.
RecipeID: this.props.navigation.state.params.ListViewClickItemHolder
})
}).then((response) => response.json())
.then((responseJson) => {
this.setState({
RecipeID : responseJson[0].RecipeID,
RecipeName : responseJson[0].RecipeName,
RecipeType : responseJson[0].RecipeType,
RecipeIngredient : responseJson[0].RecipeIngredient,
RecipeStep : responseJson[0].RecipeStep
})
}).catch((error) => {
console.error(error);
});
}
ShowAll(){
Alert.alert(
'Alert Title',
this.state.RecipeName, // **ERROR COME FROM THIS LINE**
[
{text: 'Ask me later', onPress: () => console.log('Ask me later pressed')},
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{text: 'OK', onPress: () => console.log('OK Pressed')},
],
{ cancelable: false }
)
}
render()
{
return(
<View style = { styles.MainContainer }>
<View style={{flex:1, flexDirection: 'column'}} >
<Text style={styles.textViewContainer} > {'Recipe ID = ' + this.state.RecipeID} </Text>
<Text style={styles.textViewContainer} > {'Recipe Name = '} </Text>
<TextInput
style={styles.textInput}
onChangeText={(text) => this.setState({RecipeName: text})}
value={this.state.RecipeName}
/>
<Text style={styles.textViewContainer} > {'Recipe Type = '} </Text>
<Picker
style={{width: 200}}
selectedValue={this.state.RecipeType}
onValueChange={
(itemValue, itemIndex) => {
this.setState({RecipeType: itemValue, isLoading:true})
this.componentDidMount()
this.forceUpdate()
}
}>
<Picker.Item label="Vegetarian" value="Vegetarian" />
<Picker.Item label="Fast Food" value="Fast Food" />
<Picker.Item label="Healthy" value="Healthy" />
<Picker.Item label="No-Cook" value="No-Cook" />
<Picker.Item label="Make Ahead" value="Make Ahead" />
</Picker>
<Text style={styles.textViewContainer} > {'Ingredient = '} </Text>
<TextInput
style={styles.textInput}
onChangeText={(text) => this.setState({RecipeIngredient: text})}
value={this.state.RecipeIngredient}
/>
<Text style={styles.textViewContainer} > {'Step = '} </Text>
<TextInput
style={styles.textInput}
onChangeText={(text) => this.setState({RecipeStep: text})}
value={this.state.RecipeStep}
/>
<Button
title="Show"
onPress={this.ShowAll}
color="#841584"
/>
</View>
</View>
);
}
}
The RecipeName Variable was already defined in Consturctor(State), it also able to be used/called by the Views too. But when come to the ShowAll() function, it become Undefined.
Why/How is would become undefined when the Code is already there?
Binding in Render
onChange={this.handleChange.bind(this)}
If you use an ES6 class and you want to call your function in render, React no longer autobinds. One way to resolve this is to call bind in render. But this approach actually not good. Because the function is reallocated on every render. So, there are several ways to do it.
Use Arrow Function in Render
This approach is similar to binding in render approach. You can avoid changing the this context by using an arrow function in render:
onChange={e => this.handleChange(e)}
This is another approach to do the same thing but the performance still same with binding in render. Only difference is you are not using 'this'.
Bind in Constructor
One way to avoid binding in render is to bind in the constructor.
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
This is the approach currently recommended in the React docs for “better performance in your application”. You just bind once and use every time you press the button inside your render.

How to autofocus next TextInput on react-native

I'm trying to create a passcode protected screen. The screen will uses 4 numeric input as the passcode.
The way I'm doing this is create a TextInput Component and call it 4 times in my main screen.
The problem I'm having is the TextInputs will not focus on the next one as I type the value of the previous TextInput.
I'm using refs for all PasscodeTextInput component (I've been informed that it is a legacy method but I do not know any other way, alas).
Tried this method(without creating my own component), no luck too.
METHOD
index.ios.js
import React, { Component } from 'react';
import { AppRegistry, TextInput, View, Text } from 'react-native';
import { PasscodeTextInput } from './common';
export default class ProgressBar extends Component {
render() {
const { centerEverything, container, passcodeContainer, textInputStyle} = styles;
return (
<View style={[centerEverything, container]}>
<View style={[passcodeContainer]}>
<PasscodeTextInput
autoFocus={true}
ref="passcode1"
onSubmitEditing={(event) => { this.refs.passcode2.focus() }} />
<PasscodeTextInput
ref="passcode2"
onSubmitEditing={(event) => { this.refs.passcode3.focus() }} />
<PasscodeTextInput
ref="passcode3"
onSubmitEditing={(event) => { this.refs.passcode4.focus() }}/>
<PasscodeTextInput
ref="passcode4" />
</View>
</View>
);
}
}
const styles = {
centerEverything: {
justifyContent: 'center',
alignItems: 'center',
},
container: {
flex: 1,
backgroundColor: '#E7DDD3',
},
passcodeContainer: {
flexDirection: 'row',
},
}
AppRegistry.registerComponent('ProgressBar', () => ProgressBar);
PasscodeTextInput.js
import React from 'react';
import {
View,
Text,
TextInput,
Dimensions
} from 'react-native';
const deviceWidth = require('Dimensions').get('window').width;
const deviceHeight = require('Dimensions').get('window').height;
const PasscodeTextInput = ({ ref, autoFocus, onSubmitEditing, onChangeText, value}) => {
const { inputStyle, underlineStyle } = styles;
return(
<View>
<TextInput
ref={ref}
autoFocus={autoFocus}
onSubmitEditing={onSubmitEditing}
style={[inputStyle]}
maxLength={1}
keyboardType="numeric"
placeholderTextColor="#212121"
secureTextEntry={true}
onChangeText={onChangeText}
value={value}
/>
<View style={underlineStyle} />
</View>
);
}
const styles = {
inputStyle: {
height: 80,
width: 60,
fontSize: 50,
color: '#212121',
fontSize: 40,
padding: 18,
margin: 10,
marginBottom: 0
},
underlineStyle: {
width: 60,
height: 4,
backgroundColor: '#202020',
marginLeft: 10
}
}
export { PasscodeTextInput };
Update 1
index.ios.js
import React, { Component } from 'react';
import { AppRegistry, TextInput, View, Text } from 'react-native';
import { PasscodeTextInput } from './common';
export default class ProgressBar extends Component {
constructor() {
super()
this.state = {
autoFocus1: true,
autoFocus2: false,
autoFocus3: false,
autoFocus4: false,
}
}
onTextChanged(t) { //callback for immediate state change
if (t == 2) { this.setState({ autoFocus1: false, autoFocus2: true }, () => { console.log(this.state) }) }
if (t == 3) { this.setState({ autoFocus2: false, autoFocus3: true }, () => { console.log(this.state) }) }
if (t == 4) { this.setState({ autoFocus3: false, autoFocus4: true }, () => { console.log(this.state) }) }
}
render() {
const { centerEverything, container, passcodeContainer, testShit, textInputStyle } = styles;
return (
<View style={[centerEverything, container]}>
<View style={[passcodeContainer]}>
<PasscodeTextInput
autoFocus={this.state.autoFocus1}
onChangeText={() => this.onTextChanged(2)} />
<PasscodeTextInput
autoFocus={this.state.autoFocus2}
onChangeText={() => this.onTextChanged(3)} />
<PasscodeTextInput
autoFocus={this.state.autoFocus3}
onChangeText={() => this.onTextChanged(4)} />
<PasscodeTextInput
autoFocus={this.state.autoFocus4} />
</View>
</View>
);
}
}
const styles = {
centerEverything: {
justifyContent: 'center',
alignItems: 'center',
},
container: {
flex: 1,
backgroundColor: '#E7DDD3',
},
passcodeContainer: {
flexDirection: 'row',
},
}
AppRegistry.registerComponent('ProgressBar', () => ProgressBar);
There is a defaultProp for TextInput where one can focus after component mounted.
autoFocus
If true, focuses the input on componentDidMount, the default value is false. for more information please read the related Docs.
UPDATE
After componentDidUpdate it won't work properly. In that case, one can use ref to focus programmatically.
You cannot forward the ref to <TextInput> using that way because ref is one of the special props. Thus, calling this.refs.passcode2 will return you <PasscodeTextInput> instead.
Try change to the following to get the ref from <TextInput>.
PasscodeTextInput.js
const PasscodeTextInput = ({ inputRef, ... }) => {
...
return (
<View>
<TextInput
ref={(r) => { inputRef && inputRef(r) }}
...
/>
</View>
...
);
}
Then, assign the inputRef from <PasscodeTextInput> to a variable and use focus() to switch focus (it is not deprecated as of RN 0.41.2).
index.ios.js
return (
<PasscodeTextInput
autoFocus={true}
onChangeText={(event) => { event && this.passcode2.focus() }} />
<PasscodeTextInput
inputRef={(r) => { this.passcode2 = r }}
onChangeText={(event) => { event && this.passcode3.focus() }} />
<PasscodeTextInput
inputRef={(r) => { this.passcode3 = r }}
onChangeText={(event) => { event && this.passcode4.focus() }} />
<PasscodeTextInput
inputRef={(r) => { this.passcode4 = r }} />
);
P.S: event && this.passcode2.focus() prevents focus is switched when trying to clear the old passcode and enter a new one.
we handled this style of screen with a different approach.
Rather than manage 4 individual TextInputs and handle the navigation of focus across each one (and then back again when the user deletes a character), we have a single TextInput on screen but is invisible (ie. 0px x 0px) wide which has the focus, maxLength and keyboard configuration, etc.
This TextInput takes input from the user but can't actually been seen, as each character is typed in we render the entered text as a series simple View/Text elements, styled much similar to your screen above.
This approach worked well for us with no need to manage what the 'next' or 'previous' TextInput to focus next to.
You can use focus method onChangeText as Jason stated, in addition to that adding maxLength={1} can make you jump to the next input immediately without checking what's added. (just noticed its deprecated, but still this is how I solved my problem, and should do fine until v0.36, and this link explains how you should update the deprecated function).
<TextInput
ref="first"
style={styles.inputMini}
maxLength={1}
keyboardType="numeric"
returnKeyType='next'
blurOnSubmit={false}
placeholderTextColor="gray"
onChangeText={(val) => {
this.refs['second'].focus()
}}
/>
<TextInput
ref="second"
style={styles.inputMini}
maxLength={1}
keyboardType="numeric"
returnKeyType='next'
blurOnSubmit={false}
placeholderTextColor="gray"
onChangeText={(val) => {
this.refs['third'].focus()
}}
/>
...
Please notice that my use of refs are deprecated too, but I've just copied the code since I can guarantee you that was working back then (hopefully works now too).
Finally, the main issue with this type of implementation is, once you try to remove a number with backspace your focus will jump to next one, causing serious UX issues. However, you can listen for backspace key entry and perform something different instead of focusing to next input. So I'll leave a link here for you to further investigate if you choose to use this type of implementation.
Hacky Solution to Previously Described Issue: If you check what's entered in onChangeText prop before doing anything, you can jump to next input if the value is a number, else (that's a backspace), jump back. (Just came up with this idea, I haven't tried it.)
I think the issue is that onSubmitEditing is when you hit the "return" or "enter" key on the regular keyboard... there is not one of those buttons on the keypad.
Assuming you want each input to only have one character, you could look at the onChangeText and then check if text has length 1 and call focus if the length is indeed 1.
<TextInput
ref={input => {
this.nameOrId = input;
}}
/>
<TouchableOpacity
onPress={()=>{
this.nameOrId.focus()
}}
>
<Text>Click</Text>
</TouchableOpacity>
I solve with this code:
const VerifyCode: React.FC = ({ pass, onFinish }) => {
const inputsRef = useRef<Input[] | null[]>([]);
const [active, setActive] = useState<number>(0);
const onKeyPress = ({ nativeEvent }:
NativeSyntheticEvent<TextInputKeyPressEventData>) => {
if (nativeEvent.key === "Backspace") {
if (active !== 0) {
inputsRef.current[active - 1]?.focus();
return setActive(active - 1);
}
} else {
inputsRef.current[active + 1]?.focus();
return setActive(active + 1);
}
return null;
};
return (
<View style={styles.container}>
<StyledInput
onKeyPress={onKeyPress}
autoFocus={active === 0}
ref={(r) => {
inputsRef.current[0] = r;
}}
/>
<StyledInput
onKeyPress={onKeyPress}
autoFocus={active === 1}
ref={(r) => {
inputsRef.current[1] = r;
}}
/>
<StyledInput
onKeyPress={onKeyPress}
autoFocus={active === 2}
ref={(r) => {
inputsRef.current[2] = r;
}}
/>
<StyledInput
onKeyPress={onKeyPress}
autoFocus={active === 3}
ref={(r) => {
inputsRef.current[3] = r;
}}
/>
</View>
);
};
export default VerifyCode;
I put one ref in all the inputs, and when the onKeyPress fire, the function verify if have to go back or go to next input
Solved it by removing autoFocus={true} and setting timeout.
I have a popup as a functional component and using "current.focus()" with Refs like this:
const Popup = ({ placeholder, autoFocus, showStatus, }) => { const inputRef = useRef(null); useEffect(() => {
Platform.OS === 'ios'
? inputRef.current.focus()
: setTimeout(() => inputRef.current.focus(), 40); }, [showStatus]); return (
<View style={styles.inputContainer}>
<TextInput
style={styles.inputText}
defaultValue={placeholder}
ref={inputRef}
/>
</View> };

Categories