jdmdevdotnet
jdmdevdotnet

Reputation: 1

Can't focus on React input

Having some trouble trying to focus in on an element. I have a mapped array function that spits out html with inputs. It is possible to have multiple id's, so I want to set the ref to be 'type' + Id. The two possible types are task and subtask. When I try access via this.refs.{refValue}.focus() I get a Cannot read property 'focus' of undefined

Here's my jsx:

<input className="ui-input-text" type="text" ref="subTask + {subTask.Id}" onChange={this.handleSubTaskChange.bind(this, indx, idx)} value={subTask.Name} />

Here's where I get my error

        var subTaskRef = 'subTask' + subTaskId;
        this.refs.subTaskRef.focus();

The variable subTaskId is correct, I have verified that. Perhaps I am setting the ref incorrectly?

EDIT

After following @Ori Drori's answer, here's some more code:

class Tasks extends React.Component {
focusTasks: [],
focusSubTasks: [],
constructor(props) {
    super(props);

    this.state = {
        editableTasks: [],
        editableSubTasks: [], 

        tasks: [],
        subTasks: [],            
        plannerId: this.props.plannerId,
    };

    var state = this.state;


}

and (part) of my render method

render() {
    const tasks = this.state.tasks.map((task, idx) => {
        var editable = this.state.editableTasks.filter(id => id === task.Id).length > 0;
        var editableSubTasks = this.state.editableSubTasks;
        const subTaskComponents = task.SubTasks.map((subTask, indx) => 
            <li key={subTask.Id} className="list-group-item" style={{minHeight: '50px', border: 0, backgroundColor: 'rgba(127,191,63,.42)'}}>
                    <div className="pull-left" style={{width: '50%'}}>
                        <!-- Pay attention to this line -->{editableSubTasks.filter(id => id === subTask.Id).length > 0 ? <input className="ui-input-text" type="text" ref={ (ref) => this.focusSubTasks[subTask.Id] = ref }  onChange={this.handleSubTaskChange.bind(this, indx, idx)} value={subTask.Name} /> : <span>{subTask.Name}</span>}
                    </div>
                    <div className="pull-right" style={{marginTop: '-5px', width: '50%'}}>
                        <div className="pull-right">
                             <button className="btn btn-default" onClick={() => { this.EditSubTask(task.Id, subTask.Id)}}>{editableSubTasks.filter(id => id === subTask.Id).length > 0  ? <i className="fa fa-check"></i> : <i className="fa fa-pencil-square-o"></i>}</button>
                        </div>
                    </div>
            </li>
        );

Here's where the issue seems to be (won't build)

enter image description here

Upvotes: 3

Views: 3282

Answers (2)

Solo
Solo

Reputation: 6977

Using the ref callback just to set a property on the class is a common pattern for accessing DOM elements and React creators recommend to use this pattern instead of this.refs.myRef pattern.


class MyComponent extends React.Component {

  // ..

  render() {
    return (

      <input ref={(thisEl) => { this['name' /* + subTask.Id */] = thisEl }} />
    )
  }
}

Now you can just use it as this['name' /* + subTask.Id */].focus().


However, Im not 100% sure if that could be the cause of your issue, especially because you didn't let us know if console.log(this.refs) actually has correct elements and if you didn't make mistakes.

Let me know how it works out for you.


I don't recommend to use jQuery, in other words: don't mix avoidable imperative code with declarative code. It seems like an easy solution for your issues but if you'll get the whole point of React, you'll understand that jQuery is not the easy solution, especially in long run.

Upvotes: 0

jdmdevdotnet
jdmdevdotnet

Reputation: 1

Ended up just using jQuery, it's much easier when it's one line of code. Not sure if what I'm doing is too complicated for this, but I ended up setting an id on the inputs, and just calling $(el).focus() to solve this problem. Unless someone has a working example, I will update this SO.

Upvotes: 0

Related Questions