Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot change selected text, after change value of TextInput

Tags:

react-native

I have create a sample react-native app. This app just include TextInput and a Button

export default class App extends Component {
  state = {
    inputValue: "You can change me!"
  };

  _handleTextChange = inputValue => {
    this.setState({ inputValue });
  };

  _handleSelectionChange = (event) =>{
    this.setState({seleksi : event.nativeEvent.selection});
    console.log(event.nativeEvent.selection);
  }

  _handleButtonPress = () => {
    this.setState({inputValue : "Paijo tenan"});
  };

  render() {
    return (
      <View style={styles.container}>
        <TextInput
          value={this.state.inputValue}
          onChangeText={this._handleTextChange}
          **onSelectionChange={(event)=>this._handleSelectionChange(event)}**
          style={{ width: 200, height:200, padding: 8 }}
          multiline={true}
        />

        <Button
          title="Press me"
          onPress={this._handleButtonPress}
        />
      </View>
    );
  }
}

when I set onSelectionChange prop, after Button clicked. Text selection on TextInput shows unusual.

Before button clicked, selection shows bullet start and end

Before button clicked, selection shows bullet start and end

After, Selection not show bullet start and end

After, Selection not show bullet start and end

But when I type some text on TextInput, it's work for selection.

How to make the selection works after I click the button, with onSelectionChange props on TextInput? And why this gonna be happen? how to debug?, my code looks fine

I create expo snack in here https://snack.expo.io/rJ6VxW56x

like image 805
projo Avatar asked Apr 11 '17 08:04

projo


2 Answers

I finally fixed it! put textinput value like this!

<TextInput ...>
    <Text>{this.state.inputValue}</Text>
</TextInput>
like image 155
Max Djafarov Avatar answered Oct 11 '22 09:10

Max Djafarov


I'm not entirely sure if this was your intention... but I found a hacky workaround for ensuring the selection range is the same following button press.

Start by keeping track of selection in the state:

state = {
  inputValue: 'You can change me!',
  selection: {start: 0, end: 0},
};

Use the selection prop on TextInput:

selection={this.state.selection}

Ensure you are saving selection to state in _handleSelectionChange

_handleSelectionChange = (event) => {
  this.setState({ selection: event.nativeEvent.selection });
}

Modify _handleButtonPress to store selection state before updating inputValue and use the hackish setTimeout to revert the selection after text changes. The reason for the timeout is to give the inputValue time to update which will trigger a _handleSelectionChange which we want to ignore... so we set it to previous value after text changes, selection is the same range as previously and you see the draggable bullets.

  _handleButtonPress = () => {
    const selectionBeforeChange = { start: this.state.selection.start, end: this.state.selection.end };
    this.setState({ inputValue : 'Paijo tenan' }, () => {
      setTimeout(() => {
        this.setState({ selection: selectionBeforeChange });
      }, 50);
    });
  };

I really dislike using setTimeout anywhere but this solution may work given your needs. A known problem is that if the new text (after button press) is shorter than selection range, it will not properly migrate the previous selection. I'm sure you could check for the new value's length and compare to selection/shorten selection to be a valid selection length if this is your goal.

And, as user Jaws mentions... it is good to be clear where/when you bind your functions to this. I like to bind everything in a constructor to prevent any unnecessary rebinding/keep things together.

  constructor(props) {
    super(props);
    this._handleButtonPress = this._handleButtonPress.bind(this);
    this._handleSelectionChange = this._handleSelectionChange.bind(this);
    this._handleTextChange = this._handleTextChange.bind(this);
  }
like image 38
Travis White Avatar answered Oct 11 '22 08:10

Travis White