Change input value after click on list element - javascript

I have got form with input
<form onSubmit={handleSubmit}>
<input type="search"
onChange={handleChange}
onFocus={() => setFocus({name: true})}
onBlur={() => setFocus({name: false})}
value={inputName}
/>
</form>
and the list of elements which is rendered after this input field has focus. This input field is live searcher for elements of this rendered list.
the code to render list:
<div>
{
objects.map((object, index) => {
return (
<ul>
<li key={index}>
{object.name}
</li>
</ul>
)
})
}
</div>
I want to make the action that when I click on the list element, the input field gets this element value.
In the picture below, the input field should be Object 2 after I click on Object 2 element
Due to there are two independent jsx objects, I have no idea how can I do this.

You can try to do this with a function triggered onClick on a <li> that sets the inputName value with the object.name :
<div>
<ul>
{
objects.map((object, index) => {
return (
<li key={index} onClick={() => setInputName(object.name)}>
{object.name}
</li>
)
})
}
</ul>
</div>
And by the way I think your <ul> tag should be outside the map

Related

React/JS How would I assign a specific mapped element to a state?

My search component returns a mapped list of results based on the input. Depending on the list element clicked, I want to assign it to my current stock state but I am not sure how I would access that specific element.
const selectStock = ()=>{
setSearch("");
setCurrentStock();
}
return (
<div className="searchContainer">
<form className="searchBar">
<input
className="search"
type="text"
placeholder="Search Ticker Symbol"
onChange={handleSearch}
/>
</form>
<div className="searchResults">
<ul>
{/* {stockNames.map((stockname) => {
const { name, symbol} = stockname;
return (
<li className="displaySearch" onClick={selectStock} key={symbol}>
<p>{name} ({symbol})</p>
</li>
);
})} */}
</ul>
</div>
</div>
);
}
First, you'll want to change your selectStock function to accept the stockName to which it should be set. That should be passed to your setCurrentStock function:
const selectStock = (nextStock) => {
setSearch("");
setCurrentStock(nextStock);
}
Then, pass an arrow function through to the onClick function for the row that you select:
<div className="searchResults">
<ul>
{stockNames.map((stockname) => {
const { name, symbol } = stockname;
return (
<li className="displaySearch" onClick={() => selectStock(stockname)} key={symbol}>
<p>{name} ({symbol})</p>
</li>
);
})}
</ul>
</div>
What this does is essentially create a new function for each row that's specific to itself. When that row is clicked, it triggers its own unique onClick, which passes its own stockname value through to selectStock.
You can pass the selectedStock into the selectStock function by making it a ES6 function.
See below:
const selectStock = (selectedStock)=>{
setSearch("");
setCurrentStock(selectedStock);
}
return (
<div className="searchContainer">
<form className="searchBar">
<input
className="search"
type="text"
placeholder="Search Ticker Symbol"
onChange={handleSearch}
/>
</form>
<div className="searchResults">
<ul>
{/* {stockNames.map((stockname) => {
const { name, symbol} = stockname;
return (
<li className="displaySearch" onClick={()=>selectStock(stockName)} key={symbol}>
<p>{name} ({symbol})</p>
</li>
);
})} */}
</ul>
</div>
</div>
);
You can pass other variables in the similar way if required.

React JS render list data in separate row

I am facing an issue in React Js. I want to show names data in each separate row.
const names = ['James', 'John', 'Paul', 'Ringo'[![\]][1]][1];
My Code:
return (
<div class="col-lg-8 bar-name">
<div>
{names.map(filteredName => (
<li>
{filteredName}
</li>
))}
</div>
</div>)
How can i use in div element ? What should i do?
can anyone help me?
You need to add elements to want to be displayed alongside in the List tag.
Example:
return (
<div class="col-lg-8 bar-name">
<div>
{names.map(filteredName => (
<li>
{filteredName}
<div>
Ryan
</div>
<div>
Eric
</div>
</li>
))}
</div>
)

Validating Final Form Array on Click

I am building an application with React Final Form. In the form, user needs to fill up basic input fields as well as add questions with its choices. For the questions and choices I am using FieldArray feature. So, until here everything is good and working. However, I would like to add another functionality to this form.
As you can see in the image below, this is a Card component rendered inside FieldArray. Every time user clicks Add a Question button, There will be another Card component on the page.
The feature I need is to make the Save button work on top-right corner. At the moment I don't know how should I implement the Save button but what I wanna achieve is that I want to toggle the Card component in the image to another Card component, where I display the input data by using fields.value. So, no input field. However, I want to also validate this portion of the form when I click save. This is what I don't know how to do. So, every Save button will validate its own fields and if validation passes, the Card will be toggled to another Card component where the data is read-only.
So, I need your suggestion for the validation part as well as your opinion to add this functionality.
Thanks
Edit
I've been reading the docs of FinalForm as well as ReduxForm to figure out how can I handle this situation but I couldn't figure it out yet.
I've checked the Wizard example in FinalForm docs. However I am not sure if it's suitable for my situation. Wizard has a single <form> tag present at all times on a page and when a user clicks next button, input fields switch. In my case, I might need multiple form tags as you mentioned.
I've put 3 form structures as an example. Can you tell me which way is to go?
import { Form as FinalForm } from 'react-final-form'
#1 Basic Form:
Classic way of structuring the form and it is the current situation. So, this is not the way to solve the issue.
<FinalForm onSubmit={aCustomSubmitFunction}>
{
({ handleSubmit }) => {
return (
<form onSubmit={handleSubmit}>
<Field name='firstName'>{({input}) => <input {...input} />}</Field>
<Field name='lastName'>{({input}) => <input {...input} />}</Field>
<FieldArray name='questions'>
{({ fields }) => (
<div>
{fields.map((name, index) => {
return (
<div className="card">
<Field name={`${name}.question`}>{({input}) => <input {...input} type="text" />}</Field>
<button type="button" onClick={() => fields.remove(index)}>Delete</button>
<button type="submit">Save</button>
</div>
)
})}
<button type="button" onClick={() => fields.push({ question: undefined })}>Add a Question</button>
</div>
)}
</FieldArray>
<button type="submit">Submit</button>
</form>
)
}
}
</FinalForm>
#2 Multiple forms under a single FinalForm:
Multiple forms inside a FinalForm. This seems to be the way to go, however 'save' button submits the entire form not its own form. It is using the same handleSubmit so this must be the reason, though how can I have a different handleSubmit? Wrapping the form tag that is inside FieldArray with another FinalForm?
<FinalForm onSubmit={aCustomSubmitFunction}>
{
({ handleSubmit }) => {
return (
<>
<form onSubmit={handleSubmit}>
<Field name='firstName'>{({input}) => <input {...input} />}</Field>
<Field name='lastName'>{({input}) => <input {...input} />}</Field>
<button type="submit">Submit</button>
</form>
<FieldArray name='questions'>
{({ fields }) => (
<div>
{fields.map((name, index) => {
return (
<form onSubmit={handleSubmit}>
<div className="card">
<Field name={`${name}.question`}>{({input}) => <input {...input} type="text" />}</Field>
<button type="button" onClick={() => fields.remove(index)}>Delete</button>
<button type="submit">Save</button>
</div>
</form>
)
})}
<button type="button" onClick={() => fields.push({ question: undefined })}>Add a Question</button>
</div>
)}
</FieldArray>
</>
)
}
}
</FinalForm>
#3 Multiple nested forms under a single FinalForm:
This is invalid html. So this must be wrong approach but while I was doing a research I found a thing called React Portals, which might be helpful but I think it's unnecessary.
<FinalForm onSubmit={aCustomSubmitFunction}>
{
({ handleSubmit }) => {
return (
<form onSubmit={handleSubmit}>
<Field name='firstName'>{({input}) => <input {...input} />}</Field>
<Field name='lastName'>{({input}) => <input {...input} />}</Field>
<FieldArray name='questions'>
{({ fields }) => (
<div>
{fields.map((name, index) => {
return (
<form>
<div className="card">
<Field name={`${name}.question`}>{({input}) => <input {...input} type="text" />}</Field>
<button type="button" onClick={() => fields.remove(index)}>Delete</button>
<button type="submit">Save</button>
</div>
</form>
)
})}
<button type="button" onClick={() => fields.push({ question: undefined })}>Add a Question</button>
</div>
)}
</FieldArray>
<button type="submit">Submit</button>
</form>
)
}
}
</FinalForm>
To validate only part of a form, you must split it into multiple forms, and have the "Save" button "submit" the form. The Wizard Example does this, collecting the form values from each "page" in a parent component.
Hope this helps...

React js - pass value to child to parent to another child

I am trying to pass the data from Child > parent > child
Child
{this.state.data.map((item, index) => (
<li className='card' key={index}>
<span>{item.continent} </span>
<ul className="accordion-body">
{item.regions.map((c, i) => (
<li key={i} onClick={this.props.toggleContent}>
<img src={c.flag}/> {c.country}
</li>
))}
</ul>
</li>
))}
Basically I need to get selected country and some other values from the child and pass to parent
and pass those values to another child.
My Parent
<div className="modal-header">
<h2>Choose your {title}</h2>
<a href="#" className="model-close" data-dismiss="modal" aria-label="Close"><i
className="fa fa-times-circle"></i></a>
</div>
<div className="modal-body">
{showCountry && <CountryList toggleContent={this.toggleContent}/>}
{showLanguages && <RegionList country={country} flag={flag} languages={languages}
toggleContent={this.toggleContentRegion.bind(this)}/>}
</div>
and
toggleContent = () => {
this.setState({
...this.state,
showCountry: !this.state.showCountry,
showLanguages: !this.state.showLanguages,
title: 'language',
country: 'country',
languages: [],
flag: 'flag'
});
}
I tried to use below
<li key={i} onClick={this.props.toggleContent(c.country)}>
<img src={c.flag}/> {c.country}
</li>
and access it from parent
toggleContent = (country) => {
this.setState({
...this.state,
showCountry: !this.state.showCountry,
showLanguages: !this.state.showLanguages,
title: 'language',
country: country,
languages: [],
flag: 'flag'
});
}
But, my components not working correctly When do that and always shows the 2 child component.
Are there any proper way to pass the data to parent from a json array?
So the best way I would handle this would be to make the import your parent class components into the child , place it at the very top of the child JSX but hide it by default. The modal would be fixed, background covering the full page and at a z-index higher than the rest of the child components, so that way only the modal contents are the only accessible things . You would have a state that "toggles on" the modal for each click of the item list and a close button that toggles it off. You would update the modal content and toggle it on for every click
In terms of the second child, you can just show it on the same modal
Found a way to do this :)
render() {
var toggleContent = this.props.toggleContent;
return (
<div className="modal-wrapper">
<ul className="country-list">
{this.state.data.map((item, index) => (
<li className='card' key={index}>
<span>{item.continent} </span>
<ul className="accordion-body">
{item.regions.map((c, i) => (
**<li key={i} onClick={() => toggleContent(c.country,c.flag, c.languages, c.region)} >**
<img src={c.flag}/> {c.country}
</li>
))}
</ul>
</li>
))}
</ul>
</div>
);
}
Changed below line
onClick={() => toggleContent(c.country,c.flag, c.languages, c.region)

Why does tabIndex not work after first tab to select li?

You can view my app here: https://moon.holdings
Here is the repo: https://github.com/Futuratum/moon.holdings
If you select the [ + ] Add Asset button, click in the search input and hit tab there are 2 issues.
Nothing is selected the first time, you have to tab again in order to select the first asset.
And more importantly after Bitcoin is selected, tabbing does not select the next item in the list. Instead after 4 tabs the I can see that the Coinbase button was selected instead of another li.
Here you can see that each li does correctly have a tabindex:
1st tab, nothing selected
2nd tab, Bitcoin selected
3rd tab, nothing selected
4th tab, Coinbase button selected:
The JSX of the searchModal.js component:
render() {
const { assets } = this.state;
return (
<section id="search-modal">
<header className="search-header">
<input
id="coin-search"
type="text"
placeholder="Search"
onChange={() => this.handleChange()}
/>
<button className="close-modal-x" onClick={this.closeSquareEdit} />
</header>
<ul id="coins-list">
{ assets !== 'undefined'
? assets.map((asset, i) => (
<li
key={asset.currency}
role="button"
tabIndex={i}
onFocus={() => this.setFocus(asset)}
onBlur={this.onBlur}
onClick={() => this.handleSelect(asset)}
>
{asset.name}
<span className="symbol">{asset.currency}</span>
</li>))
: <li>Loading...</li>
}
</ul>
</section>
);
}
The main container: Board.js
return (
<div id="board">
{ this.renderPortfolio(sortedAssets) }
{ edit && this.renderSquareEdit(coin) }
{ search && this.renderSearchModal() }
{ loading && moonPortfolio && <Loading /> }
{ portfolio.length === 0 && <Welcome /> }
<PlusButton toggleSearch={this.handleSearchButton} />
<Affiliates />
<Nomics />
<Astronaut logo={isTrue} />
</div>
);
The renderSearch method:
renderSearchModal() {
return (
<div>
<Search
handleClose={() => this.toggleSquareEdit(false, {})}
openEdit={this.toggleSquareEdit}
/>
<div id="overlay" onClick={this.handleSearchButton} />
</div>
);
}
Finally the affiliates.js component
const links = [
{ name: 'coinbase', link: coinbase, h4: 'Buy Bitcoin' },
{ name: 'binance', link: binance, h4: 'Buy Altcoins' },
{ name: 'changelly', link: changelly, h4: 'Swap coins' }
];
export default () => (
<div className="affiliates">
<ul>
{links.map(l => (
<a href={l.link} key={l.name} target="_blank" rel="noopener">
<li className={l.name}>
<h4>{l.h4}</h4>
</li>
</a>
))}
</ul>
</div>
);
Well, tabindex doesn't work the way you think it works.
When you select the input and press tab, it goes to the button next. Which is the next focusable element. Then ul then first li, then to the open/close button then to coinbase button
Using positive tabindex is not encouraged either.
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets
You should be fine without the tabindex property for li elements. As you could always use arrow keys to navigate the select box items.
Also check this one here: https://medium.com/#andreasmcd/creating-an-accessible-tab-component-with-react-24ed30fde86a
Which describes how to use role property, which can also be deployed to help control focus flow.

Categories

Resources