How to open keyboard on button press in react native? - react-native

I have a button and when it is pressed I would like it to open the keyboard and focus on a text input component.
For a minimal code example what I am trying to do is this-
<View>
<AddSomething
textChange={textInput => this.setState({ textInput })}
addNewItem={this.addItem.bind(this)}
textInput={this.state.textInput}
ref={not sure what goes here} //passing these as props to a text input
/>
<FloatingButton tapToAddHandler={this.onFloatingButtonPress.bind(this)} />
</View>
then some helper function where I handle the button press (this.onFloatingButtonPress)

First declare your AddSomething as below :
const AddSomething = React.forwardRef((props, ref) => (
<TextInput
ref={ref}
//your other code
/>
));
Now you can use ref and able to focus your AddSomething component as below:
<View>
<AddSomething
textChange={textInput => this.setState({ textInput })}
addNewItem={this.addItem.bind(this)}
textInput={this.state.textInput}
ref={(ref) => { this.textInputField = ref }}
/>
<FloatingButton tapToAddHandler={this.onFloatingButtonPress.bind(this)} />
</View>
Here is your onFloatingButtonPress method :
onFloatingButtonPress() {
this.textInputField.focus();
}

Proposal a react-hook version :
const inputRef = React.useRef()
return (
<TextInput ref={inputRef} />
<TouchableOpacity onPress={() => inputRef.current.focus()}>
<Text>Press</Text>
</TouchableOpacity>
)

Related

cannot set text input ref

I'm trying to switch focus between inputs on onSubmitEditing but I can't manage to pass the ref props from my custom text input to the main component.
The console log I've put in the ref doesn't log anything.
const MyCustomInput = (props) => {
<View>
<FormInput
{...props}
editable={!props.disabled}
selectTextOnFocus={!props.disabled}
disable={props.disabled}
displayOnly={props.displayOnly}
small={props.small}
placeholderTextColor={'#AFAFAF'}
/>
</View>
}
<Controller
control={control}
render={({field: {onChange, onBlur, value, ref}}) => (
<MyCustomInput
onBlur={onBlur}
onChangeText={(value: string) => onChange(value)}
value={value}
ref={(r: any) => {
console.log('r', r);
ref(r);
inputRef.current = r;
}}
/>
)}
name="myInput"
/>
Solved, I was missing a forward ref in my custom input
const MyCustomInput = fowardRef((props, ref) => {
<View>
<FormInput
{...props}
ref={ref}
editable={!props.disabled}
selectTextOnFocus={!props.disabled}
disable={props.disabled}
displayOnly={props.displayOnly}
small={props.small}
placeholderTextColor={'#AFAFAF'}
/>
</View>
)}

React Native - add specific clearButton on input field when the keyboard is open

I am trying to create a specific clear button to use on both ios and android devices. I have created a reusable component for the several fields I have. When I press the fields since the keyboard opens the X button shows in all fields not only the field I have pressed. In the code below emptyField is a value set in a parent component.
const [keyboardShow, setKeyboardShow] = useState<boolean>(false);
useEffect(() => {
const showKeyboard = Keyboard.addListener('keyboardDidShow', () => {
setKeyboardShow(true);
});
const hideKeyboard = Keyboard.addListener('keyboardDidHide', () => {
setKeyboardShow(false);
});
return () => {
showKeyboard.remove();
hideKeyboard.remove();
};
}, []);
<TouchableComponent>
<TextInput
key={currencyTypeId}
ref={forwardRef}
style={styles.input}
onChangeText={onChangeText}
value={inputValue}
editable={editable}
autoCorrect={false}
autoCompleteType='off'
returnKeyType={returnKeyType}
placeholder={placeholder}
placeholderTextColor={placeholderColor}
keyboardType={keyboardType}
/>
</TouchableComponent>
{inputValue.length > 0 && keyboardShow && (
<View style={styles.customButton}>
<TouchableOpacity onPress={emptyField}>
<CloseIcon width={12} height={12}/>
</TouchableOpacity>
</View>
)}
Seems 'keyboardDidShow' and 'keyboardDidHide' events triggered in each reusable component.
You can try another approach. Just use onBlur and onFocus events. It's isolated for each component:
<TouchableComponent>
<TextInput
onBlur={() => setIsFocused(false)}
onFocus={() => setIsFocused(true)}
key={currencyTypeId}
ref={forwardRef}
style={styles.input}
onChangeText={onChangeText}
value={inputValue}
editable={editable}
autoCorrect={false}
autoCompleteType="off"
returnKeyType={returnKeyType}
placeholder={placeholder}
placeholderTextColor={placeholderColor}
keyboardType={keyboardType}
/>
</TouchableComponent>
{inputValue.length > 0 && isFocused && (
<View style={styles.customButton}>
<TouchableOpacity onPress={() => {}}>
<CloseIcon width={12} height={12} />
</TouchableOpacity>
</View>
)}

KeyboardAvoidingView, ScrollView and Flatlist in a form

I have a form where I am using KeyboardAvoidingView and ScrollView so that when a user clicks on an input field the screen will scroll to that particular field
Within my form I have an input field that is searchable and I am using a FlatList to display the results for the user to choose from. Currently I am getting the error:
VirtualizedLists should never be nested inside plain ScrollViews
I've looked at many posts around this but am yet to find a solution (unless I've missed something):
1 - How to put FlatList inside of the ScrollView in React-native?
2 - FlatList inside ScrollView doesn't scroll
3 - How to make a FlatList scrollable inside of a ScrollView in react native?
This is what I have so far:
export const SignUpMember = ({navigation}) => {
const renderHeader = formikProps => {
return (
<>
<FormField
keyboardType={'default'}
fieldName={'firstName'}
label={'First Name'}
/>
<FormField
keyboardType={'default'}
fieldName={'lastName'}
label={'Last Name'}
/>
<FormField
onChangeText={text => {
formikProps.values.clubName = text;
searchItems(text);
}}
value={formikProps.values.clubName}
keyboardType={'default'}
fieldName={'clubName'}
label={'Club Name'}
placeholder={'Search Club By Name...'}
/>
</>
);
};
const renderFooter = formikProps => {
return (
<>
<FormField
keyboardType={'phone-pad'}
fieldName={'telephone'}
label={'Telephone'}
/>
<FormField
keyboardType={'email-address'}
fieldName={'email'}
label={'Email'}
/>
<FormField
keyboardType="default"
secureTextEntry={true}
fieldName={'password'}
label={'Password'}
type={'password'}
/>
<FormField
keyboardType="default"
secureTextEntry={true}
fieldName={'passwordConfirmation'}
label={'Confirm Password'}
type={'password'}
/>
<Button
mt="2"
bg="brand.blue"
type="submit"
onPress={formikProps.handleSubmit}>
Sign Up
</Button>
</>
);
};
return (
<KeyboardAvoidingView
keyboardVerticalOffset={headerHeight}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
<ScrollView
_contentContainerStyle={styles.container}
nestedScrollEnabled={true}>
<Box p="1" py="8" w="90%" maxW="290">
<VStack space={3} mt="5">
<Formik
initialValues={initialFormValues}
onSubmit={values => handleFormSubmit(values)}
validationSchema={userValidationSchema}>
{formikProps => (
<View>
<FlatList
nestedScrollEnabled={true}
data={flatListData}
renderItem={({item}) => (
<Pressable
onPress={() => {
formikProps.values.clubName = item.name;
setFlatListData([]);
}}>
<Text style={styles.flatList}>{item.name}</Text>
</Pressable>
)}
keyExtractor={item => item.name}
ListHeaderComponent={renderHeader(formikProps)}
ListFooterComponent={renderFooter(formikProps)}
/>
</View>
)}
</Formik>
</VStack>
</Box>
</ScrollView>
</KeyboardAvoidingView>
);
};
export default SignUpMember;
How can I piece this together?

Problem with updating state in react native component

I have an array with values i want to present and then if the user press the edit button the presentation is changed to a list of TextInput components. When done editing the user can press Save or Cancel. If Cancel is pressed the values in the textInput fields should not be saved to the original array of values.
My problem is that even when pressing Cancel the data in the original array seems to be updated.
This is the code:
`
const handlePress = (text, index) => {
const newSchedule = [...scheduleTempState]
newSchedule[index].value = text
setScheduleTempState(newSchedule)
}
const handlePress2 =()=>{
setScheduleTempState([]);
console.log("handlepress2")
setEdit(false)
}
const handlePress3 =()=>{
setScheduleTempState(scheduleState);
console.log("handlepress3")
setEdit(true)
}
return (
edit
?
<View style={styles.scheduleRow}>
<View style={styles.buttonView}>
<TouchableOpacity onPress = { ()=>{saveSchedule(projectId,scheduleState);updateClient() ;setEdit(false)}} >
<MaterialIcons name="save" size={16} color="green" />
</TouchableOpacity>
<TouchableOpacity onPress = { ()=>{handlePress2()}} >
<MaterialIcons name="cancel" size={16} color="red" />
</TouchableOpacity>
</View>
<View>
<FlatList
horizontal = {true}
data={scheduleTempState}
keyExtractor={item => item.id}
renderItem={({item, index}) => {
return (
<View style={styles.decimalInputView}>
<TextInput
style={styles.cellInput}
onChangeText={(text) => {handlePress(text, index)}}
value = {item.value} />
</View>
)
}}
/>
</View>
</View>
:
<View style={styles.scheduleRow}>
<View style={styles.buttonView}>
<TouchableOpacity onPress = { ()=>handlePress3()} >
<MaterialIcons name="edit" size={14} color="black" />
</TouchableOpacity>
</View>
<View >
<FlatList
horizontal={true}
data={scheduleState}
renderItem={renderScheduleItem}
keyExtractor={item => item.id}
/>
</View>
</View>
);
}`
I guess my problem has something to do with states not being updated, but i can not see how the edited values can be saved when i press cancel.
Problem:
You are updating the scheduleTempState by referencing your scheduleState. So when you mutate scheduleTempState, it also mutates the scheduleState.
Solution: Please use spread operator to scheduleState which can help to create a new copy of a reference.
const handlePress3 =()=>{
setScheduleTempState([...scheduleState]);
...
}
Suggestion: It would be better to use explanatory names for function. It will make the code more readable. For example:
onChangeText() instead of handlepress()
onCancelEditing() instead of handlepress2()
onEdit instead of handlepress3()
Hope you will get the idea.

React Native clear text multiple TextInput boxes

I found example code on a facebook React Native page which shows how to use setNativeProp to clear text on a click but I can't see how to do it with multiple text boxes. Here is the code:
var App = React.createClass({
clearText() {
this._textInput.setNativeProps({text: ''});
},
render() {
return (
<View style={styles.container}>
<TextInput ref={component => this._textInput = component}
style={styles.textInput} />
<TouchableOpacity onPress={this.clearText}>
<Text>Clear text</Text>
</TouchableOpacity>
</View>
);
}
});
The ref seems to be fixed in the function so will always target the same TextInput box. How can I alter the function to target any TextInput box I indicate?
This should work. Notice that the ref on the TextInput needs to be the one you call from the clearText functino.
var App = React.createClass({
clearText(fieldName) {
this.refs[fieldName].setNativeProps({text: ''});
},
render() {
return (
<View style={styles.container}>
<TextInput ref={'textInput1'} style={styles.textInput} />
<TouchableOpacity onPress={() => this.clearText('textInput1')}>
<Text>Clear text</Text>
</TouchableOpacity>
<TextInput ref={'textInput2'} style={styles.textInput} />
<TouchableOpacity onPress={() => this.clearText('textInput2')}>
<Text>Clear text</Text>
</TouchableOpacity>
</View>
);
}
});
Updated my answer to clear different fields.
You can also use something like this to clear the text of TextInput.
clearText(fieldName) {
this.refs[fieldName].clear(0);
},