Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TextInput onChangeText callback was not invoked on Android #23663

Closed
tianjyan opened this issue Feb 27, 2019 · 9 comments
Closed

TextInput onChangeText callback was not invoked on Android #23663

tianjyan opened this issue Feb 27, 2019 · 9 comments
Labels
Bug Component: TextInput Related to the TextInput component. Platform: Android Android applications. Stale There has been a lack of activity on this issue and it may be closed soon.

Comments

@tianjyan
Copy link

🐛 Bug Report

When I set TextInput's padding is 0 and keyboardType is numeric on Android, onChangeText was not invoked when I was typing numbers.

To Reproduce

See "Code Example" section.

Expected Behavior

onChangeText should be invoked when I am typing numbers.

Code Example

You can also get the whole project at https://github.com/tianjyan/textinput_issue .

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 * @lint-ignore-every XPLATJSCOPYRIGHT1
 */

import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, TouchableOpacity, TextInput} from 'react-native';

const instructions = Platform.select({
  ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
  android:
    'Double tap R on your keyboard to reload,\n' +
    'Shake or press menu button for dev menu',
});

type Props = {};

type State = {
  codes: Array<string>,
};

export default class App extends Component<Props, State> {
  textInput: Object;

  bindRef = (ref: Object) => { this.textInput = ref; };

  constructor(props: Props) {
    super(props);
    this.state = {
      codes: ['', '', '', '', '', ''],
    };
    this._onChangeText = this._onChangeText.bind(this);
  }

  render() {
    return (
      <View style={styles.container}>
        <TouchableOpacity
          activeOpacity={1}
          onPress={() => {
            this.textInput.focus();
          }}
        >
          <TextInput
            ref={this.bindRef}
            autoFocus
            maxLength={6}
            keyboardType="numeric"
            onChangeText={this._onChangeText}
            style={styles.textInput}
          />
          {this._renderItemsView()}
        </TouchableOpacity>
      </View>
    );
  }

  _onChangeText: (text: string) => void;

  _onChangeText(text: string) {
    const codes = text.split('');
    for (let i = 0; i < 6; i++) {
      if (i >= text.length) {
        codes[i] = '';
      }
    }
    this.setState({
      codes,
    });
  }

  _renderItemsView() {
    return (
      <View style={styles.itemsContainer}>
        {
          this.state.codes.map((code, index) => (
            <View
              key={index}
              style={styles.item}
            >
              <Text style={styles.text}>
                {code}
              </Text>
            </View>
          ))
        }
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'stretch',
    backgroundColor: '#F5FCFF',
  },
  textInput: {
    width: 0,
    height: 0,
    // If you change the padding to 1, the onChangeText will be invoked if you type numbers.
    padding: 0,
    backgroundColor: 'transparent',
  },
  itemsContainer: {
    marginTop: 52,
    marginEnd: 24,
    marginStart: 24,
    flexDirection: 'row',
    justifyContent: 'space-between',
  },
  item: {
    width: 32,
    height: 42,
    borderBottomWidth: 1,
    borderBottomColor: 'grey',
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    color: 'black',
    fontWeight: 'bold',
    fontSize: 32,
    textAlign: 'center',
  },
});

Environment

React Native Environment Info:
System:
    OS: macOS 10.14.3
    CPU: (4) x64 Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz
    Memory: 111.20 MB / 16.00 GB
    Shell: 5.3 - /bin/zsh
Binaries:
    Node: 8.11.3 - /usr/local/opt/node@8/bin/node
    Yarn: 1.7.0 - /usr/local/bin/yarn
    npm: 5.6.0 - /usr/local/opt/node@8/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
SDKs:
    iOS SDK:
    Platforms: iOS 12.1, macOS 10.14, tvOS 12.1, watchOS 5.1
    Android SDK:
    API Levels: 18, 23, 25, 26, 27, 28
    Build Tools: 23.0.1, 23.0.2, 26.0.1, 26.0.2, 26.0.3, 27.0.3, 28.0.1, 28.0.2, 28.0.3
    System Images: android-27 | Google Play Intel x86 Atom
IDEs:
    Android Studio: 3.2 AI-181.5540.7.32.5056338
    Xcode: 10.1/10B61 - /usr/bin/xcodebuild
npmPackages:
    react: 16.6.3 => 16.6.3 
    react-native: 0.58.5 => 0.58.5 
npmGlobalPackages:
    create-react-native-app: 1.0.0
    react-native-cli: 2.0.1
    react-native-create-library: 3.1.2
    react-native-log-ios: 1.0.1
@react-native-bot react-native-bot added Component: TextInput Related to the TextInput component. Platform: Android Android applications. labels Feb 27, 2019
@kaelxeth
Copy link

kaelxeth commented Feb 27, 2019

@tianjyan try moving your renderItemsView function above TextInput

render() {
    return (
      <View style={styles.container}>
        <TouchableOpacity
          activeOpacity={1}
          onPress={() => {
            this.textInput.focus();
          }}
        >
          {this._renderItemsView()}
          <TextInput
            ref={this.bindRef}
            autoFocus
            maxLength={6}
            keyboardType="numeric"
            onChangeText={this._onChangeText}
            style={styles.textInput}
          />
        </TouchableOpacity>
      </View>
    );
  }

@tianjyan
Copy link
Author

Cool, that works. @jacoahmad Could you tell me the theory ?

@kaelxeth
Copy link

I'm not sure what's the root cause is, but looking at your code, if you want to have a hidden input, I think you don't have to put your TextInput inside TouchableOpacity.

You can write it this way

render() {
    return (
      <View style={styles.container}>
        <TouchableOpacity
          activeOpacity={1}
          onPress={() => {
            this.textInput.focus();
          }}
        >
          {this._renderItemsView()}
        </TouchableOpacity>
        <TextInput
          ref={this.bindRef}
          autoFocus
          maxLength={6}
          keyboardType="numeric"
          onChangeText={this._onChangeText}
          style={styles.textInput}
        />
      </View>
    );
  }

@tianjyan
Copy link
Author

@jacoahmad Thank you for your response. You are right, I don't have to put the input inside the TouchableOpacity. But put it inside TouchableOpacity does not break the language specific. So I think this is still a bug.

@kaelxeth
Copy link

kaelxeth commented Feb 27, 2019

@tianjyan Yes, it won't break the language. TextInput is tap-able out of the box, wrapping it with a component that has event listener and passes a function to it sounds wrong.

I'm not sure how to avoid an event listener on the parent of TextInput which is TouchableOpacity. Imagine textInput.focus() fires multiple times each time you press TouchableOpacity

@tianjyan
Copy link
Author

tianjyan commented Feb 27, 2019

@jacoahmad I think avoiding the event listener is not the topic for this issue. I can still input ,/./- by using my code.

@CatapultJesse
Copy link

TextInput inside touchable opacity event firing behaviour could be related to: #23720

@umair-khanzada
Copy link

umair-khanzada commented Mar 11, 2019

I am facing the same issue onChangeText didn't call.

import React, {Component} from 'react';
import {View, TextInput} from 'react-native';

export default class App extends Component {
  constructor(props){
    super(props);
    this.state = {email: ''}
  }
  render() {
    return (
      <View >
        <TextInput value={this.state.email} onChangeText={(t) => {
          console.log("running", t)
          this.setState({email: t})
        }}
        />
      </View>
    );
  }
}

The interesting thing is when I put default value TextInput render with that value but again I type onChangeText didn't call.
onChangeText only call when I cut the value using cross key ×

Ex:

this.state = {email: 'something'}

input value => something
press a => input value still =>something         //onChangeText didn't call
press b => input value still =>something         //onChangeText didn't call
...

press × => input value changed =>somethin     //onChangeText called
press × => input value changed =>somethi      //onChangeText called

@stale
Copy link

stale bot commented Aug 2, 2019

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Aug 2, 2019
@tianjyan tianjyan closed this as completed Aug 2, 2019
@facebook facebook locked as resolved and limited conversation to collaborators Aug 2, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug Component: TextInput Related to the TextInput component. Platform: Android Android applications. Stale There has been a lack of activity on this issue and it may be closed soon.
Projects
None yet
Development

No branches or pull requests

6 participants