How to disable backspace key in TextInput in React Native? - react-native

I'm using TextInput and i'd like the first symbol in the TextInput to be constant. So if the length of the text is one symbol i could ignore backspaces and onChangeText event could be ignored.
The following code doesn't work, the onChangeText event occurs anyway. Please, is there any solution?
<Input
onChangeText = { (text) => onTextChange(text) }
onKeyPress = { (e) => {
if(e.nativeEvent.key === 'Backspace') {
e.preventDefault();
e.stopPropagation();
}
} }
/>

Could You try this:
<TextInput
onKeyPress={({ nativeEvent }) => {
if(nativeEvent.key === 'Backspace'){
//It was a backspace
}
}}
/>
I think you are just forgetting the .key after nativeEvent

I guess you could try to set a lock for the text input and pass it to the editable attribute of the text input. When onKeyPress is triggered, lock the text input when the key is backspace and release the lock otherwise. An example would be:
const [inputLock, setInputLock] = useState(false);
.......
<TextInput
onKeyPress={({ nativeEvent }) => {
if (nativeEvent.key === "Backspace") {
setInputLock(true);
} else {
setInputLock(false);
}
}}
editable={!inputLock}
..../>

Related

onSubmitEditing: Error: Maximum update depth exceeded

There is a textinput in my screen. Besides that there is a search icon. Upon pressing the search icon, this.searchmethod() is called and searching is performed. I also want to perform searching upon pressing the "search", "done", "go" or "enter" button of the keyboard. I tried onSubmitEditing like shown in below, which resulted in the error:
Error: Maximum update depth exceeded
My code:
<TextInput
onChangeText = {
text => {
this.setState({
searchtag: text
})
}
}
onSubmitEditing={this.searchmethod()}
onFocus = {() => {
if (this.state.searchtag != "")
this.setState({
searchtag: ''
}, () => {
this._refreshData()
})
}
}
/>
<TouchableWithoutFeedback
onPress = {
() => {
this.searchmethod()
}
} >
<View>
<FearIcon name = "search" size = {25}/>
</View>
</TouchableWithoutFeedback>
Kindly guide me how I can perform searching upon pressing "done" or etc key on Keyboard. Thanks in advance.
Try doing this
onSubmitEditing={() => this.searchmethod()}
Instead of onFocus, refreshData in onChangeText like
this.setState({
searchtag: text
},
() => this._refreshData();
)

Picker onValueChange() called twice

I want to support localization using react-18next.
This component shows a Picker, sets a LocalStorage key (the selected language) and change the app language.
I noticed the onValueChange method is called twice. The first call (using a proper selection tap action on a Picker item) have the correct parameter (the language I have chosen), the second call have the value of the first Picker item, whenever the values is (!).
Example: if I select the English Picker item, I see the Picker switch to English (first _changeLanguage() call), and then again to "Device" (second _changeLanguage() call). I'm sure it's an async ops problem, not sure where..
#translate(['settings', 'common'], { wait: true })
export default class Settings extends Component {
state = {};
constructor(props) {
super(props);
}
componentWillMount() {
this.getLang();
}
async _changeLanguage(ln) {
const { t, i18n, navigation } = this.props;
console.warn("_changeLanguage: ",ln)
await this.promisedSetState({lang:ln})
if(ln=="device") {
console.warn("removing lang setting")
await AsyncStorage.removeItem('#App:lang');
} else {
console.warn("lang setting: ", ln)
await AsyncStorage.setItem('#App:lang', ln);
i18n.changeLanguage(ln)
}
};
//get Language from AsyncStorage, if it has been previously set
async getLang() {
const value = await AsyncStorage.getItem('#App:lang');
console.warn("getLangfrom asyncstorage:", value)
if(value) await this.promisedSetState ({lang:value})
}
promisedSetState = (newState) => {
return new Promise((resolve) => {
this.setState(newState, () => {
resolve()
});
});
};
render() {
const { t, i18n, navigation } = this.props;
const { navigate } = navigation;
return (<View>
<Picker
selectedValue={this.state.lang}
onValueChange={(itemValue, itemIndex) =>this._changeLanguage(itemValue) }>
<Picker.Item color="#666" label="detected from device" value="device" />
<Picker.Item label="English" value="en" />
<Picker.Item label="Deutsch" value="it" />
</Picker>
</View>);
}
}
The code is based on the react-i18next Expo example
https://github.com/i18next/react-i18next/tree/master/example/v9.x.x/reactnative-expo
I'm not sure if this belongs here but if anyone is encountering the problem of onValueChange firing twice and is using react-native-picker-select instead of the default Picker then this solution may work for you.
I ended up using the itemKey property instead of value and setting the key of each item to be the same as its value. Note the example item would end up shaped like so: { key: 'value1', value: 'value1', label: 'Your Label' } where the key and value are identical.
Original Code:
<RNPickerSelect
style={styles.picker}
value={value}
onValueChange={this.onValueChange}
placeholder={placeholder}
items={options}
/>
Fixed Code:
<RNPickerSelect
style={styles.picker}
itemKey={value}
onValueChange={this.onValueChange}
placeholder={placeholder}
items={options}
/>
I got my inspiration from this: GitHub issue.
Searching around the react-native Picker seems bugged.
This quickfix solved my problem https://github.com/facebook/react-native/issues/13351#issuecomment-450281257

react-native reseting TextInput after ClearTextOnFocus

I am building a form in React-Native and have set ClearTextOnFocus to true as it is easier to handle dynamic formating for editing.
I am trying to add a reset function by setting all local state to the redux store, but if the user has not typed anything in a selected TextInput, the local state has not changed, and react native does not re-render the TextInput; leaving it blank.
Anyone have any thoughts on how I can unclear the TextInput or force React to re-render. Code is a work in progress, but here are the relevant bits.
Thanks
class GoalScreen extends Component {
componentWillMount = () => this.setPropsToState();
onReset = () => {
this.setPropsToState();
}
onChange = text => this.setState({ [text.field]: text.input });
setPropsToState = () => {
const { name } = this.props.goal;
this.setState({ name });
};
render() {
const { name } = this.state;
return (
<View style={styles.screenContainer}>
<Text style={styles.text}> Name </Text>
<TextInput
placeholder="a brand new bag"
keyboardType="default"
autoCorrect={false}
style={styles.inputField}
clearTextOnFocus
onChangeText={text => this.onChange({ input: text, field: 'rate' })}
value={name}
/>
</View>
}
}
So, I'm not using Redux, and my use case might be a bit different than yours, but I thought my solution might still be relevant here, if only to confirm that (after hours of wrangling with this) it appears that passing true to the clearTextOnFocus prop prevents further updates to a TextInput component.
I tried every conceivable workaround (like setNativeProps(), forceUpdate()) but nothing worked, so I ended up having to basically write my own logic for clearing and resetting the input text.
This component should 1) clear input text on focus and then 2) reset it to its previous value if the user hasn't pressed a key:
class ResettableInput extends Component {
state = {
Current: this.props.value,
Previous: ""
};
KeyPressed = false;
//cache current input value for later revert if necessary, and clear input
onFocus = () => {
this.setState({ Previous: this.state.Current, Current: "" });
};
//record whether key was pressed so input value can be reverted if necessary
onKeyPress = () => {
this.KeyPressed = true;
};
onChangeText = text => {
this.setState({ Current: text });
};
//if no key was pressed, revert input to previous value
onBlur = () => {
if (!this.KeyPressed) {
this.setState({ Current: this.state.Previous, Previous: "" });
}
};
render = () => {
return (
<TextInput
onChangeText={this.onChangeText}
value={this.state.Current}
onBlur={this.onBlur}
onFocus={this.onFocus}
onKeyPress={this.onKeyPress}
/>
);
};
}

How to add Form from dropdown clicked in react native?

i'm new in react native, i want to add Form if dropdown clicked. i use ModalDropdown library. but, i'm confuse to add that. thanks
this is my code
const OPTION_STATUS = ['option1', 'option2', 'option3'];
class.....{
return(
<ModalDropdown
options={this.state.status_option}
defaultIndex={-1}
defaultValue={'Please select Status Update'}
onDropdownWillShow={this._status_willShow.bind(this)}
onDropdownWillHide={this._status_willHide.bind(this)}
onSelect={(idx, value) => this._status_onSelect(idx, value)}
/>
);
_status_willShow() {
setTimeout(() => this.setState({
status_option: OPTION_STATUS,
}), 2000);
}
_status_willHide() {
this.setState({
status_option: null,
});
}
_status_onSelect(idx, value) {
console.debug(`idx=${idx}, value='${value}'`);
this.setState({status: value});
}
}
You need to toggle the form in some way inside your _status_onSelect function.
Example:
_status_onSelect(idx, value) {
console.debug(`idx=${idx}, value='${value}'`);
this.setState({status: value, showForm: true});
}
And then you can add the UI elements in your render method like so:
{this.state.showForm ?
<View>
// Your form content here
</View>
: null }

Detecting send/submit button in a multi-line TextInput

The React Native TextInput component doesn't support the onSubmitEditing event if it specified as a multi-line input.
Is there a way to detect when the user presses the enter/submit/send (depending on which keyboard layout is specified) button after entering some text?
I realize this is an old post, but I stumbled here from Google and wanted to share my solution. Because of some things that needed to happen in the case of submit, vs simply blurring, I wasn't able to use onBlur to interpret submit.
I utilized an onKeyPress listener to track the Enter key, and then proceeded with the submit. (Note, this is currently only supported in iOS until this PR is merged.)
// handler
onKeyPress = ({ nativeEvent }) => {
if (nativeEvent.key === 'Enter') {
// submit code
}
};
// component
<TextInput
autoFocus={true}
blurOnSubmit={true}
enablesReturnKeyAutomatically={true}
multiline={true}
onChangeText={this.onChangeText}
onKeyPress={this.onKeyPress}
returnKeyType='done'
value={this.props.name}
/>
Note, the blurOnSubmit is still required to prevent the return key from being passed to your onChangeText handler.
On iOS this should work according to the documentation.
Use the onBlur function:
Callback that is called when the text input is blurred
In combination with the ios only blurOnSubmit:
If true, the text field will blur when submitted. The default value is
true for single-line fields and false for multiline fields. Note that
for multiline fields, setting blurOnSubmit to true means that pressing
return will blur the field and trigger the onSubmitEditing event
instead of inserting a newline into the field.
I'll try testing this.
Edit:
Done testing
blurOnSubmit doesn't work like it's supposed to in react-native 0.14.2. Even when set to true, the return/done button and enter key just create a newline and do not blur the field.
I'm not able to test this on newer versions at the moment.
Try it! It works in the middle of the line also!
<TextInput
placeholder={I18n.t('enterContactQuery')}
value={this.state.query}
onChangeText={text => this.setState({ query: text, allowEditing: true })}
selection = {this.state.selection}
onSelectionChange={(event) => this.setState({ cursorPosition: event.nativeEvent.selection, selection: event.nativeEvent.selection, allowEditing: true })}
onSubmitEditing={() => {
const { query, cursorPosition } = this.state;
let newText = query;
const ar = newText.split('');
ar.splice(cursorPosition.start, 0, '\n');
newText = ar.join('');
if (cursorPosition.start === query.length && query.endsWith('\n')) {
this.setState({ query: newText });
} else if (this.state.allowEditing) {
this.setState({
query: newText,
selection: {
start: cursorPosition.start + 1,
end: cursorPosition.end + 1
},
allowEditing: !this.state.allowEditing
});
}
}}
multiline = {true}
numberOfLines = {10}
blurOnSubmit={false}
editable={true}
// clearButtonMode="while-editing"
/>
constructor(props) {
super(props);
this.state = {
query: '',
cursorPosition: [0,0],
selection: null,
allowEditing: true
}
}
constructor () {
super()
this.state = {
text : '',
lastText : '',
inputHeight:40
}
}
writing(text){
this.setState({
text : text
})
}
contentSizeChange(event){
if(this.state.lastText.split("\n").length != this.state.text.split("\n").length){
this.submitTextInput();
}else{
this.setState({
inputHeight : event.nativeEvent.contentSize.height
})
}
}
submitTextInput(){
Alert.alert('submit input : ' + this.state.text);
this.setState({
text : ''
})
}
render() {
return (
<View style={{flex:1,backgroundColor:'#fff'}}>
<TextInput
style={{height:this.state.inputHeight}}
multiline={true}
onChangeText={(text) => this.writing(text)}
onContentSizeChange={(event) => this.contentSizeChange(event)}
onSubmitEditing={() => this.submitTextInput()}
value={this.state.text}
/>
</View>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react-dom.min.js"></script>