22

I have a custom TextInput. When I edit the first TextInput and hit the "Next" in the keyboard, I want it to focus the second TextInput. I have searched before in Stack Overflow and it seems I can do it using ref. However I'm not sure how to do that with custom TextInput.

Here is my basic CustomTextInput code:

let CustomTextInput = React.createClass({
    propTypes: {
        refName: React.PropTypes.string,
        returnKeyType: React.PropTypes.string,
        onSubmitEditing: React.PropTypes.func
    },

    getDefaultProps: function(){
        return {
            refName: "",
            returnKeyType: "default",
            onSubmitEditing: () => {}
        }
    },

    render: function(){
        return(
            <View>
                <TextInput 
                    ref={this.props.refName}
                    returnKeyType={this.props.returnKeyType}
                    onSubmitEditing={this.props.onSubmitEditing}
                />
            </View>
        )
    }
});

module.exports = CustomTextInput

And here is my Parent class that calls it:

let MyParent = React.createClass({
    render: function(){
        return(
            <View>
                <CustomTextInput
                    refName={'firstNameInput'},
                    returnKeyType={'next'}
                    onSubmitEditing={(event) => { 
                        this.refs.lastNameInput.focus();
                    }}
                />
                <CustomTextInput
                    refName={'lastNameInput'}
                />
            </View>
        )
    }
});

Right now, when I press the Next in the keyboard, after selecting the firstName, I got an exception:

undefined is not an object (evaluating '_this2.refs.lastNameInput.focus')

I'm not sure what I did wrong there.. Any help is appreciated. :)

SherylHohman
  • 16,580
  • 17
  • 88
  • 94
prinnny
  • 299
  • 1
  • 3
  • 12

5 Answers5

34

Let's start from the CustomTextInput component.

export default class CustomTextInput extends Component {

componentDidMount() {
    if (this.props.onRef != null) {
        this.props.onRef(this)
    }
}

onSubmitEditing() {
    this.props.onSubmitEditing();
}

focus() {
    this.textInput.focus()
}


render() {
    return (
        <View>
            <View style={this.state.isFocused ? styles.onFocusedStyle : styles.onBlurStyle}>
                <TextInput
                    ref={input => this.textInput = input}
                    onSubmitEditing={this.onSubmitEditing.bind(this)}
                />
            </View>

            <Text style={styles.errorMessageField}>{this.state.errorStatus && this.props.errorMessage}</Text>
        </View>
    );
}}

Here i have a sample customTextInput. Important things to note here is the componentDidMount(), focus() method and ref property in the TextInput view in render method.

  1. componentDidMount() method passes the ref of the whole CustomTextInput component to it's parent component. Through that reference we will call the focus method of CustomTextInput component from the parent component.

  2. focus() method here focuses the textInput inside the CustomTextInput component by using the ref of TextInput component inside the CustomTextInput component.

  3. The ref property of TextInput stores the reference of the TextInput. This reference is used by the focus() method.

Now let's see the parent component

export default class ParentComponent extends Component {
constructor(props) {
    super(props);

    this.focusNextField = this.focusNextField.bind(this);
    this.inputs = {};
}


focusNextField(id) {
    this.inputs[id].focus();
}

render() {
    return (
        <ScrollView
            contentContainerStyle={{paddingBottom:100}}
            keyboardDismissMode={'on-drag'}
            scrollToTop={true}>
            <View>
                    <View style={{marginTop: 10}}>
                        <CustomTextInput
                            onRef={(ref) => {
                                this.inputs['projectName'] = ref;
                            }}
                            onSubmitEditing={() => {
                                this.focusNextField('projectDescription');
                            }}
                            />
                    </View>
                    <View style={{marginTop: 10}}>
                        <CustomTextInput
                            onRef={(ref) => {
                                this.inputs['projectDescription'] = ref;
                            }}
                            onSubmitEditing={() => {
                                this.focusNextField('subDivision');
                            }}
                        />
                    </View>
                    <View style={{marginTop: 10}}>
                        <CustomTextInput
                            onRef={(ref) => {
                                this.inputs['subDivision'] = ref;
                            }}
                            onSubmitEditing={() => {
                                this.focusNextField('plan');
                            }}
                           />
                    </View>

                    <View style={{marginTop: 10}}>
                        <CustomTextInput
                            onRef={(ref) => {
                                this.inputs['plan'] = ref;
                            }}
                    </View>
            </View>
        </ScrollView>
    );
}}

Here in the parent component we store the ref of each CustomTextInput with onRef property and when the submit button from keyboard is pressed we call the focus method of the next CustomTextInput and the focus method of CustomTextInput focuses the TextInput inside the child component.

Mahdi Bashirpour
  • 17,147
  • 12
  • 117
  • 144
Ashik
  • 1,035
  • 12
  • 15
1

Here is a solution is you are using functional component:

Your custom component need to use React.forwardRef

const CustomTextInput = React.forwardRef((props, ref) => {
    return (
        <TextInput
            {...props}
            ref={ref}
        />
    );
});

export default CustomTextInput;

The parent component that imports your custom component:

import React, { createRef } from 'react';

const ParentComponent = () => {
    let customTextInputRef = createRef();

    return (
        <View>
            <CustomTextInput
                onSubmitEditing={() => customTextInputRef.current.focus()}}
            />

            <CustomTextInput
                ref={customTextInputRef}
            />
        </View>
    );
};
0

Here is a solution that worked for me — basically you make a reference within your custom component, which you can access from your reference in your parent component:

let CustomTextInput = React.createClass({
    propTypes: {
        refName: React.PropTypes.string,
        returnKeyType: React.PropTypes.string,
        onSubmitEditing: React.PropTypes.func
    },

    getDefaultProps: function(){
        return {
            refName: "",
            returnKeyType: "default",
            onSubmitEditing: () => {}
        }
    },

    render: function(){
        return(
            <View>
                <TextInput 
                    ref="input"
                    returnKeyType={this.props.returnKeyType}
                    onSubmitEditing={this.props.onSubmitEditing}
                />
            </View>
        )
    }
});

module.exports = CustomTextInput

And in the parent component:

let MyParent = React.createClass({
    render: function(){
        return(
            <View>
                <CustomTextInput
                    refName={'firstNameInput'},
                    returnKeyType={'next'}
                    onSubmitEditing={(event) => { 
                        this.lastNameInput.refs.input.focus();
                    }}
                />
                <CustomTextInput
                    refName={ref => this.lastNameInput = ref}
                />
            </View>
        )
    }
});
0
let CustomTextInput = React.createClass({
    componentDidMount() {
        // this is to check if a refName prop is FUNCTION; 
        if (typeof this.props.rex === "function") {
            this.props.refName(this.refs.inp);
        }
    }

    render: function() {
        return(
            <View>
                <TextInput ref={"inp"}/>
            </View>
        )
    }
});

let MyParent = React.createClass({
    render: function() {
        return (
            <View>
                <CustomTextInput
                    refName={ (firstNameInput) => this.firstNameInput = firstNameInput }
                />
            </View>
        )
    }
});
Sure
  • 23
  • 2
  • 3
-1

try this:

let AwesomeProject = React.createClass({
    onSubmitEditing:function(event){
        if (this.myTextInput !== null) {
          this.myTextInput.focus();
        }
    },
    render(){
        return(
            <View>
                <CustomTextInput
                    returnKeyType={'next'}
                    onSubmitEditing={this.onSubmitEditing}
                />
                <CustomTextInput
                    refName={(ref) => this.myTextInput = ref}
                />
            </View>
        )
    }
});
cityvoice
  • 2,409
  • 4
  • 14
  • 25