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?
Related
I have two fields that show a modal when clicked on. I want to make one disabled if I select anyone first. I am using react-bootstrap for this project
<>
<div className='add-edit-product'>
<div className='d-flex align-items-center justify-content-center error-info mb-3'>
<img src={`../../../assets/img/about/${data.currencyHedge && data.marginFinancing ? "error-info-success.png" : "error-info.png"}`} className='me-3' />
{data.currencyHedge && data.marginFinancing ?
<p className='success'>Risks are acceptable due to mitigants</p> :
<p className='error'>The below risks require your attention</p>
}
</div>
<div className='form'>
<h2 className='mb-3'>Exchange rate risk</h2>
{data.currencyHedge && data.marginFinancing ? <p>No risk</p> :
<div>
{/*clicking on either of this tab will show a modal*/}
<div className='risk-tab' onClick={() => { setcurrencyHedgeModal(true); setSelected("currencyHedge") }}>
<h3>Enter a currency hedge</h3>
<img src={`../../../assets/img/about/${data.currencyHedge ? "correct-success.png" : "correct (1).png"}`} />
</div>
<div className='risk-tab' onClick={() => {setfinancingSufficientlyModal(true); setSelected("marginFinancing")}}>
<h3>Margin the financing sufficiently</h3>
<img src={`../../../assets/img/about/${data.marginFinancing ? "correct-success.png" : "correct (1).png"}`} />
</div>
</div>
}
</div>
</div>
<div className='footer_'>
<button onClick={() => hendelCancel()} className="footer_cancel_btn">cancel</button>
<button onClick={() => { nextStep() }} className='footer_next_btn'> Next</button>
</div>
{currencyHedgeModal && <CurrencyHedgeModal show={currencyHedgeModal} onHide={() => setcurrencyHedgeModal(false)} getModalData={(e) => modalGetData(e)} type={selected} />}
{financingSufficientlyModal && <FinancingSufficientlyModal show={financingSufficientlyModal} onHide={() => setfinancingSufficientlyModal(false)} getModalData={(e) => setData({ ...data, marginFinancing: e })} />}
</>
how can I add the logic to disable the next field if anyone is selected first. the image below is the form. (the green check mark shows when each form is filled and saved)
Question answer 1
Yes, if you want both inputs to trigger the opening of the modals you have to set onClick prop on both.
This depends on implementation and what do you specifically mean by disable an input. There are a couple of possible scenarios:
2.1 You may add a disabled class like so:
className={`${isOpened ? "disabled" : ""}`}
and then write some css.
2.2 You might rewrite onClick to just return when the modal is already opened instead of opening the second modal like so:
onClick={() => {
if (isOpened) return
setOpened(true)
}
P.S. You may need to add a second boolean flag to your state if you want this behaviour on both modals / inputs
Original answer
You have to use useState hook with a boolean flag isOpened
const [isOpened, setOpened] = useState(false)
Then update the state when clicking on yout input field
onClick={() => setOpened(true)}
Finally in your input fields you can use isOpened to disable them however you want, using styles or other logic.
P.S. Don't forget to call setOpened(false) when closig your modal
I have this WP API data that I'm fetching in to a component called "HostingCard". I am mapping through this component which renders three cards. While mapping through these I am assigning a key to each of them.
`{hostings.map((hosting) => (
<HostingCard key={hosting.id} hosting={hosting} setHosting={setHostings} />
))}`
Each card has one of these titles "Pro", "Standard" and "Basic".
I made it so that once a card is clicked a new component appears. This component is called "ContactFormular".
Now in the "ContactFormular" component I want to display the information that was on the card that was clicked. is this possible?
Here's the code that opens a new component once the card/button is clicked:
import ContactFormular from './ContactFormular'
const HostingCard = ({post, handleSubmit, hosting, setHosting, showContactDialog, setShowContactDialog, ssl, setPro, pro, key}) => {
return (
<div className='noselect hosting-options'>
<input type="radio" id={post.acf.hosting} name="startup" />
<div className='card selected-card'>
<form onSubmit={handleSubmit}>
<label for={post.acf.tilvalg} className='label'>
<div className='card-header'>
<h5>{hosting.acf.title}</h5>
<p>{hosting.acf.beskrivelse}</p>
</div>
<div className='pakke-detaljer'>
<div>
<p style={{display: hosting.acf.deltaljer ? 'block' : 'none'}}>{hosting.acf.deltaljer}</p>
</div>
</div>
<div className='button-header' onClick={() => setPro(false)}>
<button className='btn' onClick={() => setShowContactDialog(true)}>Vælg</button>
</div>
</label>
</form>
</div>
<ContactFormular key={hosting.id} post={post} hosting={hosting} setHosting={setHosting} showContact={showContactDialog} setShowContact={setShowContactDialog} handleSubmit={handleSubmit} ssl={ssl} pro={pro} setPro={setPro}/>
</div>
)
}
It looks like you're passing in showContactDialog as a parameter and using that to decide whether or not to show this new component right? That means you need showContactDialog to be true for only the one you clicked on, and false for the others. ie each component needs a different state variable. It looks like you might be sharing the same state variable between all components. It's impossible to tell unless you share a reproducible example
Im new in reactjs and I create a list of card by mapping in reactjs but I want my first card be clicked as a default at the first load what can i do for this code.
<div className="d-flex">
{data && data.length > 0
? data.map((item, index) => {
return (
<>
<div className="box-stock" onClick={() => selectData(item)}>
<div className="top-stock skewed p-5">
<h1>{item.symbol}</h1>
<strong className="text-center">
<span> (0.25)</span>
{item.stockNum}
</strong>
<Label className="text-center">
EPS:<span className="text-white">{item.EPS}</span>
</Label>
<Label className="text-center">
P/E:<span className="text-white">{item.PE}</span>
</Label>
</div>
</div>
</>
);
})
: 'no data'}
</div>
You can use useEffect hook to run program once it renders. Here, in useEffect pass empty array as a dependency so, that it runs only once.
useEffect(() => {
selectData(data[0])
}, [])
You can add click event on first load using javascript. The button will trigger the event on first load and you will get your first card clicked. Here is the code:
document.getElementsByClassName("box-stock").click()
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 😊
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?