14

On my TextInput change text, I detect whether the user pushed the @ button for mentions.

onChangeText(text){
    const suggestTrigger = text.match(/\B@[A-Za-z0-9]*$/i) //grab "@" trigger
    const searchQuery = (suggestTrigger && suggestTrigger.length > 0) ? suggestTrigger[0] : null;
    this.setState({
        searchQuery: searchQuery
    })
}

Then, in my render, I do:

<TextInput 
    autoCapitalize={this.state.searchQuery ? "none" : "sentences"}
    autoCorrect={this.state.searchQuery ? false : true}
    onChangeText={this.onChangeText}
/>

However, even when I do this, the autoCorrect does not turn off.

I still see this:

enter image description here

This is causing problems because oftentimes the system replaces the entire mention with a different word altogether.

How can I turn autoCorrect and autoCapitalize off when the user pushes the @ button? ' I have even tried rendering an entirely different , but the behavior remains.

TIMEX
  • 259,804
  • 351
  • 777
  • 1,080
  • This seems to work for me. https://snack.expo.io/B1PMIxzTm – gtfargo Nov 08 '18 at 17:46
  • @gtfargo it may work on snack but it doesn't work on real device (exact code) – TIMEX Nov 08 '18 at 20:02
  • which version of react-native are you using? – lazreg87 Nov 13 '18 at 18:21
  • Would you please upload a sample project? – Mojtaba Hosseini Nov 15 '18 at 10:04
  • @MojtabaHosseini, Absolutely it is an issue from `iOS` native side and should be fixed from the native side of the project, but I add an innovative solution for solving this problem. – AmerllicA Nov 15 '18 at 13:40
  • I think so, I was planing to investigate and try to fix it from native side and tell you the solution. So you found a solution for it? – Mojtaba Hosseini Nov 15 '18 at 13:46
  • @MojtabaHosseini, Thanks a lot, I found a way and post it as answer it this current post. – AmerllicA Nov 15 '18 at 21:45
  • @TIMEX, One another thing that is not related to your question. please do not use `regex` in `react native` projects. if your regex has a bug and user insert a damn pattern it causes to CPU spike and CRASH, and you can not find it out why the app crashed, read [this link](https://medium.com/@liran.tal/node-js-pitfalls-how-a-regex-can-bring-your-system-down-cbf1dc6c4e02). Also, don't use ternary, unless there is not any other way. for your case you could write `autoCorrect={!this.state.searchQuery}`. – AmerllicA Nov 16 '18 at 08:23
  • Do you find any way to disable auto-correction for iOS devices on its keyboard? –  Aug 13 '19 at 11:10

3 Answers3

13

TL;DR: you should close and re-launch your keyboard after the TextInput autoCorrect toggling value.

Buddy, this is not your fault, I had the same issue on autoFocus of react native TextInput component. I set a state name for the TextInput editable prop and then with the pressing pencil button I change the editable props. The designer told me after the TextInput made editable the cursor should be focused, so I use the isEditable state for autoFocus prop, see below:

state = {
  isEditable: false
};

handleEdit = () => {
  const { isEditable } = this.state;
  this.setState({ isEditable: !isEditable });
};

<TextInput
  autoFocus={isEditable}
  editable={isEditable}
  style={styles.textNameEditable}
  defaultValue={text}
  numberOfLines={1}
/>

enter image description here

Then I press the edit button and it turns to:

enter image description here

But it is not focused and the Keyboard didn't launch, I sought and found this link, the TextInput does not change/update some of its props after componentDidMount. ☹️. Also, it is not different in iOS or Android, both of them has this issue, I used ref to focus on this TextInput after the isEditable state made true. see following code:

<TextInput
  editable={isEditable}
  style={styles.textNameEditable}
  defaultValue={text}
  numberOfLines={1}
  ref={input => {
    this.input = input;
  }}
/>

componentDidUpdate() {
  const { isEditable } = this.state;
  if (isEditable) {
    this.input.focus();
  }
}

And your case:

Absolutely you can not use ref because the autoCorrect should render with react native and it is not like focus() and blur() so JavaScript cannot access to it.

I make a test shape for your case, I create another button like a star for toggling autoCorrect value alongside my edit button. the filled star means autoCorrect is true and the lined star means autoCorrect is false, now see the test area code and view:

state = {
  isEditable: false,
  correct: true
};

handleCorrect = () => {
  const { correct } = this.state;
  this.setState({ correct: !correct });
};

<TextInput
  autoCorrect={correct}
  editable={isEditable}
  style={styles.textNameEditable}
  defaultValue={text}
  numberOfLines={1}
  ref={input => {
    this.input = input;
  }}
/>

enter image description here

In the above photo, it is so clear the autoCorrect rendered as true, so it is enabled:

enter image description here

When I write a wrong Persian word the auto-correction show its suggestion, now time to press the star button:

enter image description here

Wow, the autoCorrection is false in the above situation but still we see the auto-correction of the cellphone. it is just like autoFocus it is rendered in the first render and after it, the TextInput could not change/update its props. suddenly I press edit button:

enter image description here

And I press the edit button again, so surely, you realized the autoCorrect is false now, ok now see what I saw:

enter image description here

The autoCorrect remained false by my double pressing edit button and now the auto-correction of device disappears completely. I don't know it is a bug or my bad understanding but I realized in this test area, for update autoCorrect value, we should do something after changing its value to close the iPhone keyboard and then re-launch it. the main thing that TextInput has issued is the launched keyboard.

For my test, when I pressed the edit button the editable prop of the TextInput is changed to false and the keyboard is closed, so when I pressed the edit button again, the TextInput get focused and keyboard re-launched with new autoCorrect value. This is The Secret.

Solution:

You should do something, to close and open again the iOS keyboard with the new autoCorrect value. for the test case that I wrote for your question, I decided to do a hybrid innovative solution, using ref and the callback of setState:

handleCorrect = () => {
  const { correct } = this.state;
  this.input.blur(); //-- this line close the keyboard
  this.setState({ correct: !correct },
    () => {
      setTimeout(() => this.input.focus(), 50);
      //-- above line re-launch keyboard after 50 milliseconds
      //-- this 50 milliseconds is for waiting to closing keyborad finish
    }
  );
};


<TextInput
  autoCorrect={correct}
  editable={isEditable}
  style={styles.textNameEditable}
  defaultValue={text}
  numberOfLines={1}
  ref={input => {
    this.input = input;
  }}
/>

enter image description here

And after pressing the star button the keyboard close and re-launch and the auto-correction disappear completely.

enter image description here

Note: obviously, I summarized some other codes like destructuring and writing class or extends and etc for better human readability.

AmerllicA
  • 29,059
  • 15
  • 130
  • 154
1

The problem isn't in your code completely(except Regex part which didn't work in my device) but how the React Native renders Keyboard.
I created a sample that along with your initial code also changes backgroundColor of the screen.
You will find that color changes instantly when '@' is entered whereas the keyboard doesn't.
Unless you reload the keyboard. For this, if you un-comment the code it dismisses keyboard once and once you tap back on textInput the new Keyboard without autoCorrect and autoCapitalize is shown.

    state = {
    searchQuery: null,
    isFocused: true,
  }
  constructor(props) {
    super(props);
    this.onChangeText = this.onChangeText.bind(this);
}

onChangeText = (val) => {
  const suggestTrigger = val.match(/@[A-Za-z0-9]*$/i) //grab "@" trigger
  const searchQuery = (suggestTrigger && suggestTrigger.length > 0) ? suggestTrigger[0] : null;
  // Un comment this to reload
  // if(searchQuery && this.state.isFocused) {
  //   this.setState({
  //     isFocused: false
  // });
  // Keyboard.dismiss();
  //   // this.myTextInput.focus()
  // }
  this.setState({
      searchQuery: searchQuery
  })
}
  render() {
    const { searchQuery } = this.state
    return (
      <View style={[styles.container,
        {
        backgroundColor: searchQuery ? "red": "green"}
      ]}>
        <TextInput 
        style={{width: 300, height: 50, borderWidth: 1}}
        ref={(ref)=>{this.myTextInput = ref}}
          autoCapitalize={searchQuery ? "none" : "sentences"}
          autoCorrect={searchQuery ? false : true}
          onChangeText={this.onChangeText}
        />
      </View>
    );
  }

Since now we know the main cause of error may be a better solution can be reached.

AmerllicA
  • 29,059
  • 15
  • 130
  • 154
Jerin
  • 3,657
  • 3
  • 20
  • 45
1

I have 2 suggestions: First, have you tried using the autoCorrect fallback?

spellCheck={this.state.searchQuery ? false : true}

Second, have you tried with native code (Obj-C / Swift)?

import { Platform, TextInput, View } from 'react-native';
import { iOSAutoCorrect } from './your-native-code';

const shouldWork = Platform.OS === 'ios' ? <iOSAutoCorrect /> : <TextInput 
autoCapitalize={this.state.searchQuery ? "none" : "sentences"}
autoCorrect={this.state.searchQuery ? false : true}
onChangeText={this.onChangeText} />

return (<View>{shouldWork}</View>);

In iOSAutoCorrect you should use a UITextView. Then set its proper value depending on your condition:

textField.autocorrectionType = UITextAutocorrectionTypeNo; // or UITextAutocorrectionTypeYes

I have free-coded, thus the code is untested and might contain bugs.

AmerllicA
  • 29,059
  • 15
  • 130
  • 154
Gillsoft AB
  • 4,185
  • 2
  • 19
  • 35