Reputation: 316
I have data being rendered in the various div and I would like to select/focus the div when user press up/down arrow.
For selecting the div using up/down key I see using ref and ForewardRef for child component we can toggle the focus but still struggling to figure it out how to achieve this in typescript code.
I am new to this react so any suggestion or improvement on the below code is welcome.
Below is my code.
Option.ts
export interface option {
id:number;
label:string;
value:string;}
App.tsx
import React, {useRef, useEffect} from 'react';
import { option } from './option';
import Options from './options';
export default function App() {
const options : option[] = [
{ id:0, label : "Option 1", value:"12000"},
{ id:1, label : "Option 2", value:"10000" },
{ id:2, label : "Option 3", value:"11000"},
{ id:3, label : "Option 4", value:"23000" }
];
const [invTheme, setInvTheme] = React.useState("10000");
const firstRef = React.createRef<HTMLDivElement>();
const checkedRef = React.createRef<HTMLDivElement>();
useEffect(() => {
if (checkedRef.current) {
checkedRef.current.focus();
} else if (firstRef.current) {
firstRef.current.focus();
}
}, []);
return (
<div className="App">
{
options.map((option, i) => {
const {id, label, value} = option;
const checked = invTheme === value;
return (
<div key={i}>
<Options id={id} label={label} value={value} checked={checked}
onChange={() =>{
setInvTheme(value);
}}/>
<br></br>
</div>
)
})
}
</div>
);
}
Options.tsx
import React, {useEffect} from 'react'
import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
flexGrow: 1,
},
div: {
padding: theme.spacing(2),
margin: 'auto',
maxWidth: 700,
border:`1px solid Gray`
},
selectedDiv: {
padding: theme.spacing(2),
margin: 'auto',
maxWidth: 700,
border: `2px solid Blue`
}
}),);
export default function Options(props:any) {
const classes = useStyles();
//const [selectedDiv, setSelectedDiv] = React.useState(false);
//useEffect(()=>{
//if(checked) setSelectedDiv(true);
//},[])
const handleOnClick = (e:any) => {
if (e.type === "click" && e.clientX !== 0 && e.clientY !== 0) {
//setSelectedDiv(true);
onChange({target:value});
}
};
const { id, label, value, onChange, checked } = props;
console.log("id: "+ id+" checked "+ checked);
return (
<div>
<div className={checked ? classes.selectedDiv : classes.div} onClick={handleOnClick}>
<Grid container spacing={2}>
<Grid item>
<input id={id} type="radio" name="type" aria-label={label} checked={checked} value={value} onChange={onChange}/>
</Grid>
<Grid item >
{label}
</Grid>
</Grid>
</div>
</div>
);}
Upvotes: 1
Views: 709
Reputation: 12
This is how I solved it.
I made use of the checked props to control the style property of the div.
find below the codes:
options.tsx:
import React, {useEffect} from 'react'
import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
flexGrow: 1,
},
div: {
padding: theme.spacing(2),
margin: 'auto',
maxWidth: 700,
border:`1px solid Gray`,
},
selectedDiv: {
padding: theme.spacing(2),
margin: 'auto',
maxWidth: 700,
border:`1px solid Gray`,
},
selected: {
}
}),);
export default function Options(props:any) {
const classes = useStyles();
const [selectedDiv, setSelectedDiv] = React.useState(false);
const { id, label, selected, value, onChange, checked } = props;
useEffect(()=>{
if(selected) setSelectedDiv(true);
},[])
const handleOnClick = (e:any) => {
if (e.type === "click" && e.clientX !== 0 && e.clientY !== 0) {
setSelectedDiv(true);
onChange({target:value});
}
};
return (
<div>
<div className={selectedDiv ? classes.selectedDiv :classes.div} onClick={handleOnClick}style = {checked && selectedDiv? {border: `2px solid Blue`,maxWidth: 700,}:{}} >
<Grid container spacing={2} >
<Grid item>
<input id={id} type="radio" name="type" aria-label={label} checked={checked} value={value} onChange={onChange}/>
</Grid>
<Grid item >
{label}
</Grid>
</Grid>
</div>
</div>
);}
App.tsx:
import React, {useRef, useEffect} from 'react';
import { option } from './option';
import Options from './options'
export default function App() {
const options : option[] = [
{ id:0, label : "Option 1", selected : false, value:"12000"},
{ id:1, label : "Option 2", selected : true, value:"10,000" },
{ id:2, label : "Option 3", selected : false, value:"10000"},
{ id:3, label : "Option 4", selected : false, value:"23000" }
];
const [invTheme, setInvTheme] = React.useState("12000");
const firstRef = React.createRef<HTMLDivElement>();
const checkedRef = React.createRef<HTMLDivElement>();
useEffect(() => {
if (checkedRef.current) {
checkedRef.current.focus();
} else if (firstRef.current) {
firstRef.current.focus();
}
}, []);
return (
<div className="App">
{
options.map((option, i) => {
const {id, label, selected, value} = option;
const checked = invTheme === value;
return (
<div key={i} >
<Options id={id} label={label} selected={selected} value={value} checked={checked}
onChange={() =>{
setInvTheme(value);
}} />
<br></br>
</div>
)
})
}
</div>
);
}
Upvotes: 0