Reputation: 11829
I have several input fields in a table (each row has an input field) and each of them are named dynamically like so:
<table>
<tr>
<td>
<input
key={name}
type="text"
value={label}
name={name}
/>
<span>Edit</span>
</td>
</tr>
</table>
Note I am mapping on some object to render each <td />
that contains an input field.
What I'd like to happen is when I click on "Edit" for that particular row, the input field on the same row will become focused.
What I am seeing from React docs is how to trigger this focus if you have a predefined set of input fields and you're able to do createRef()
for each field.
But how do you do it if your input fields are dynamically rendered and there could possibly X number of them (depending on the object being mapped)?
Upvotes: 2
Views: 2649
Reputation: 15698
You can create an empty array to store your refs
. Then as you map
over your data to create your inputs, create and push that ref
via the ref
attribute and call-back.
See working sandbox: https://codesandbox.io/s/interesting-roentgen-q64jl
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const list = [{ name: "apple", label: "seed" }, { name: "you", label: "cat" }];
class App extends React.Component {
constructor(props) {
super(props);
this.refsArr = [];
}
focusIntoInput = index => {
this.refsArr[index].focus();
};
render() {
return (
<table>
<tr>
{list.map(({ name, label }, index) => {
return (
<td>
<input
ref={ref => this.refsArr.push(ref)}
key={name}
type="text"
value={label}
name={name}
/>
<span onClick={() => this.focusIntoInput(index)}>Edit</span>
</td>
);
})}
</tr>
</table>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
In the focusIntoInput
click-handler, the index
passed will always correspond to that ref
in the refs
array.
Upvotes: 1
Reputation: 72673
Why not dynamically create the ref
while you map over the object?
{elements.map(() => {
const ref = React.createRef();
return <td>
<input
key={name}
type="text"
value={label}
name={name}
ref={ref}
/>
<span onClick={event => {
ref.current.focus()
}}>Edit</span>
</td>
})}
Upvotes: 1
Reputation: 1681
You can create an multiple refs that maps to each item in your table like the example below.
const rows = [
{ id: "a", name: "Panel 1" },
{ id: "b", name: "Panel 2" },
{ id: "c", name: "Panel 3" }
];
const refs = useRef(new Map()).current;
return (
<div>
<table>
{rows.map(row => (
<tr>
<td>
<input
label={row.name}
ref={inst =>
inst === null ? refs.delete(row.id) : refs.set(row.id, inst)
}
type="text"
/>
<span onClick={() => refs.get(row.id).focus()}>Edit</span>
</td>
</tr>
))}
</table>
</div>
Here is a link to a working sandbox.
Upvotes: 3