reactjs - how to get focused virtual element - reactjs

I have an input list. And want to know how to get current focused inputbox:
{list.map((item, index) => {
return <div>
<label>{item.name}</label>
<input {...item} />
</div>
})}
My thought is adding onFocus and onBlur function in each inputbox and saved in state. Is that a better way for this?

Related

How to disable tab button for specific inputs in ReactJS?

I have inputs on a few pages which I animate through. You have to click the button to get the next page and the next round of inputs, however when you get to the end of each page, you can hit the tab button and it focuses on the next input field which throws off the animation flow and display. Can I disable the tab button?
If all you want to do is prevent the field from receiving focus from a tab, you can set the tabIndex attribute to -1.
<form>
<input type="text" />
<input type="text" />
<button>button</button>
<input type="text" tabIndex="-1" />
</form>
If your goal is to disable "tabbing out" of an input field, you can listen to the keyDown event, and if the keyCode is 9 (value for Tab), then preventDefault on the event:
function MyComponent() {
return <input onKeyDown={(e) => { if (e.keyCode === 9) e.preventDefault() }} />
}
Rest of your code stays the same; i.e. however you handle input change:
function MyComponent() {
const [value, setValue] = React.useState('');
return (
<input
value={value}
onChange={(e) => setValue(e.target.value)}
onKeyDown={(e) => {
if (e.keyCode === 9) e.preventDefault();
}}
/>
);
}
From an accessibility and user experience perspective, I'd suggest not disabling Tab functionality. Some of your users might not have a mouse/touch input device or capability, or might want or prefer to use the keyboard exclusively for navigation. Tab is the natural way to advance among inputs, links, and buttons on web pages and it's best if you can preserve the functionality. Is there a way to deliver your animation experience while preserving Tab navigation?
Here's a sandbox to show you how to do this using React refs. Essentially, you can use the ref to store the DOM element you want to modify, making it really reusuable. In this case we just want to set that input's tabIndex to -1
https://codesandbox.io/s/vigilant-fermat-vihnc
function App() {
const skipInputRef = React.createRef();
useEffect(() => {
skipInputRef.current.tabIndex = -1;
}, []);
return (
<div className="App">
<input />
<input />
<input ref={skipInputRef} placeholder="skip" />
<button>Click</button>
</div>
);
}

How to use hooks in multiple rendered inputs?

I'm creating the form to my app. Problem i'm facing is whenever i click add and generate another row of inputs i got an "Rendered more hooks than during the previous render" error.
I have a "benefit" input with checkbox. When user checks it i want to render another 2 inputs (in the same row) with KPI. Hook works perfectly fine if there is only one row. When i add another row the error occurs.
const renderBenefitFields = (benefit, index, fields) => {
const [hidden, setHidden] = useState(false);
return (
<div key={index}>
<InputGroup>
<Input
name={`${benefit}.projectBenefitData`}
type="text"
component={renderField}
label="Benefit of the project"
/>
<InputGroupAddon addonType="append">
<InputGroupText>
<Input
addon
type="checkbox"
aria-label="Mesurable benefit?"
onChange={() => setHidden(!hidden)}
/>
</InputGroupText>
<InputGroupText>Benefit mesurable </InputGroupText>
</InputGroupAddon>
<Trash
className="align-middle"
size={25}
onClick={() => fields.remove(index)}
/>
Show KPI inputs? {hidden === false ? "false" : "true"}
</InputGroup>
</div>
);
};
const renderBenefits = ({ fields }) => (
<div>
{fields.map(renderBenefitFields)}
<PlusCircle
className="align-baseline"
size={24}
onClick={() => fields.push({})}
/>
</div>
);
Perfect solution would be: when user checks the box react will show another two inputs.
As Ross Hunter mentioned,
1. You should capitalize your component, i.e. RenderBenefitFields
2. No mutation on state/props, in onClick={() => fields.push({})}
In addition, you should call your RenderBenefitFields in renderBenefits as following:
{fields.map((props, index) => <RenderBenefitFields key={index} {...props} />)}
P.S. You can use a unique key instead of index, depending on your situation.
The name of user-defined components needs to be capitalized.
The onClick callback in PlusCircle looks like it's directly mutating state. That's a big problem for React, and almost certainly the root of your issue. I can explain further if you need sometime I'm not on mobile 😊

Navigate with tabIndex when elements where hidden

Summary
I want to understand how the tabulation navigation works on browser, in order to perform custom input with suggestion field on React.
Objective
The objective is to provide 2 custom input to the use with suggestion dropdown. When I click to my input, the dropdown shows correctly and I can navigate through the tabulation key to my suggestions. But when I try to navigate to the next input, the dropdown shows but I can't navigate through my second dropdown suggestion.
Code example
I have the following JSX code:
class InputDropdown React.Component {
render() {
return(<div>
<div id="input1" className="input-wrapper" onMouseEnter={...} onMouseLeave={...} onBlur={...}>
<input className={"input"}
value={this.state.search_input}
onKeyDown={(e) => e.keyCode==13?this.props.validate(this.state.search_input)}
onFocus={this.setState(display_dropdown_input1: true)}
/>
<div className={"dropdown-wrapper" + this.state.display_dropdown_input1?"":"hidden"}>
{this.props.suggestion.map((suggestion, index) =>
<div className="suggestion"
tabIndex={0}
onKeyDown={(e) => e.keyCode==13?this.props.validate(suggestion.text)}
onBlur={index+1==this.props.suggestion.length?this.setState({display_dropdown_input1:false})}
>{suggestion.text}</div>)}
</div>
</div>
<div id="input2" className="input-wrapper" onMouseEnter={...} onMouseLeave={...} onBlur={...}>
<input className={"input"}
value={this.state.search_input}
onKeyDown={(e) => e.keyCode==13?this.props.validate(this.state.search_input)}
onFocus={this.setState(display_dropdown_input2: true)}
/>
<div className={"dropdown-wrapper" + this.state.display_dropdown_input2?"":"hidden"}>
{this.props.suggestion.map((suggestion, index) =>
<div className="suggestion"
tabIndex={0}
onKeyDown={(e) => e.keyCode==13?this.props.validate(suggestion.text)}
onBlur={index+1==this.props.suggestion.length?this.setState({display_dropdown_input2:false})}
>{suggestion.text}</div>)}
</div>
</div>
</div>)
}
}
Question
It's as if the tabulation navigations road is prepared on the first tabulation pressed and if element appear after this press they are not taken in count.
Is it possible to perform it in React?

React - Setting state to target with onClick method

I am trying to recreate a tabs component in React that someone gave me and I am getting stuck while getting the onClick method to identify the target.
These are the snippets of my code that I believe are relevant to the problem.
If I hardcode setState within the method, it sets it appropriately, so the onClick method is running, I am just unsure of how to set the tab I am clicking to be the thing I set the state to.
On my App page:
changeSelected = (event) => {
// event.preventDefault();
this.setState({
selected: event.target.value
})
console.log(event.target.value)
};
<Tabs tabs={this.state.tabs} selectedTab={this.state.selected}
selectTabHandler={() => this.changeSelected}/>
On my Tabs page:
{props.tabs.map(tab => {
return <Tab selectTabHandler={() => props.selectTabHandler()} selectedTab={props.selectedTab} tab={tab} />
})}
On my Tab page:
return (
<div
className={'tab active-tab'}
onClick={props.selectTabHandler(props.tab)}
>
{props.tab}
</div>
When I console.log(props.tab) or console.log(event.target.value) I am receiving "undefined"
There are a few issues causing this to happen. The first issue is that you wouldn't use event.target.value in the Content component because you aren't reacting to DOM click event directly from an onClick handler as you are in Tab, instead you are handling an event from child component. Also keep in mind that event.target.value would only be applicable to input or similar HTML elements that have a value property. An element such as <div> or a <span> would not have a value property.
The next issues are that you aren't passing the tab value from Tabs to Content and then from within Content to it's changeSelected() handler for selectTabHandler events.
In addition the onClick syntax in Tab, onClick={props.selectTabHandler(props.tab)} is not valid, you will not be able to execute the handler coming from props and pass the props.tab value. You could instead try something like onClick={() => props.selectTabHandler(props.tab)}.
Content - need to pass tab value coming from child to changeSelected():
render() {
return (
<div className="content-container">
<Tabs
tabs={this.state.tabs}
selectedTab={this.state.selected}
selectTabHandler={tab => this.changeSelected(tab)}
/>
<Cards cards={this.filterCards()} />
</div>
);
}
Tabs - need to pass tab coming from child to selectTabHandler():
const Tabs = props => {
return (
<div className="tabs">
<div className="topics">
<span className="title">TRENDING TOPICS:</span>
{props.tabs.map(tab => {
return (
<Tab
selectTabHandler={tab => props.selectTabHandler(tab)}
selectedTab={props.selectedTab}
tab={tab}
/>
);
})}
</div>
</div>
);
};
export default Tabs;
Also don't forget the unique key property when rendering an array/list of items:
<Tab
key={tab}
selectTabHandler={tab => props.selectTabHandler(tab)}
selectedTab={props.selectedTab}
tab={tab}
/>
Here is a forked CodeSandbox demonstrating the functionality.

ReactiveSearch only autocomplete

I want to use ReactiveSearch library only for autocomplete with submit.
const Search = () => (
<div className="search-field">
<ReactiveBase
app="good-books-ds"
credentials="nY6NNTZZ6:27b76b9f-18ea-456c-bc5e-3a5263ebc63d"
>
<div className="row">
<div className="col">
<DataSearch
dataField={['original_title', 'original_title.search']}
categoryField="authors.raw"
componentId="BookSensor"
/>
</div>
</div>
</ReactiveBase>
</div>
)
export default Search
I tried making the input as above with <DataSearch ... /> and it works, but it doesn't have submit option. I tried to wrap it with form, but after enter or select value it doesn't fire.
Any suggestions?
https://opensource.appbase.io/reactive-manual/search-components/datasearch.html
you need to read the doc carefully there is onValueChange handler so when you type in something you can set the state first set the initial state state = {searchText: ""} at the top after that in Data search prop you can do the following
<DataSearch onValueChange = {(e) => this.setState({searchText: value})} />
now make you own button and submit the value in the state for example this.state.searchText
ReactiveSearch now supports an onValueSelected prop which is perfect for usecases where you are only interested in utilizing the selected value (either selecting a suggestion or hitting Enter key). Docs and example usage:
<DataSearch
...
onValueSelected={(value) => console.log('The selected value is', value)}
/>

Resources