Formatting of cascading dropdown using react select - reactjs

I have a cascading dropdown which is like below:-
Its code is like below:-
render() {
return (
<div>
<center>
<h5>
Select cluster and server type
<hr />
<select
value={this.state.selectcluster}
onChange={this.selectclusterChange.bind(this)}
>
<option>-- Select --</option>
{this.state.clusterslist.map((x) => {
return <option>{x.label}</option>;
})}
</select>
<select
value={this.state.selectserver}
onChange={this.routeChange}
>
<option>----selection disabled----</option>
{this.state.servertype.map((x) => {
return <option>{x}</option>;
})}
</select>
</h5>
</center>
</div>
);
}
}
Now if i want its formatting like below:-
Here i have used react-select. Is there any way to improve formatting of my above code using react-select?

I have changed the code to work like below:-
render() {
return (
<div className='container pt-5'>
<center>
<h5>
Select cluster and server type
<hr />
<Select className="custom-select"
onChange={this.selectclusterChange.bind(this)}
value={this.state.selectcluster}
options={this.state.clusterslist.map((x) => {
return {label: x.label};
})}
/>
<Select
onChange={this.routeChange}
value={this.state.selectserver}
options={this.state.servertype.map((y) => {
return {label: y};
})}
/>
</h5>
</center>
</div>
);
}
}
Its working like below:-
Thanks for the helpful link and suggestions.

Related

How filter an object in component with props?

I would like to filter and display onclick the choice by id in a component by props.
APP COMPONENT: I display the list
<div className="App-container">
<div className="App-container-left">
<p>Liste des factures</p>
<div>
{datas.factures.map((datas) => (
<>
<ul>
<li key={datas.id}>
N° : {datas.id}|{datas.dateFacture}-{datas.client} -
Montant : {datas.montant} €
</li>
<button onClick={toggleFact} id={datas.id}>
Voir
</button>
</ul>
</>
))}
</div>
</div>
<div className="App-container-right">
{view && <ViewFact obj={datas} selectId={datas.id} />}
</div>
<div />
</div>
CHILD COMPONENT: onclick I would like display the id
export default function ViewFact(props) {
//filter with id
const filtered = props.obj.factures.filter((id) => {
return props.obj.factures.id === id;
});
return (
<>
<div>ViewFact Component</div>
<div>
{filtered.map((datas) => (
<>
<ul>
<li key={datas.id}>
N° : {datas.id}|{datas.dateFacture}-{datas.client} - Montant :{" "}
{datas.montant} €
</li>
</ul>
</>
))}
</div>
</>
);
}
If I understood correctly, you need to see the clicked item details, so
<ViewFact obj={datas} selectId={datas.id} />
should has as input only the clicked item. (you need to implement setCurrentSelectedItem so as to store the item in your local state)
<button onClick={setCurrentSelectedItem}>
Voir
</button>
<ViewFact obj={currentSelectedItem} />
and finally your compoment will be
export default function ViewFact({ datas }) {
return (
<>
<div>ViewFact Component</div>
<div>
N° : {datas.id}|{datas.dateFacture}-{datas.client} - Montant :{" "}
{datas.montant} €
</div>
</>
);
}

onChange event won't fire in .map function React

I cannot get this onChange event to fire? The goal is to render multiple options from a drop down, from some data I have, then console log "hello" when any of the options is clicked...
It doesn't seem to want to let me use onChange or onClick events in my rendered option elements. If i can simply console log first , then i can figure out everything else. I only posted the necessary code but I can post the rest if needed!
const SlideData = [
{
title: "Slide 0",
},
{
title: "Slide 1",
},
{
title: "Slide 2",
},
];
export default SlideData;
let options = SlideData.map((item, index) => (
<option
key={index}
value={index}
onChange={() => {
console.log("hello");
}}
>
{item.title}
</option>
));
<select className={styles.select} onChange={goto}>
<option>--Select--</option>
{options}
</select>
option tag doesn't support onChange. You can use onClick instead.
onClick={() => {
console.log("hello");
}}
goal was to pass the index and console log it technically. so I guess this worked for me
const slideRef = useRef();
const goto = ({ target }) => {
slideRef.current.goTo(parseInt(target.value, 10));
console.log(target.value);
};
const options = SlideData.map((item, index) => (
<option key={index} value={index}>
{item.title}
</option>
));
return (
<div className={styles.container}>
<Slide ref={slideRef} {...properties}>
<div className={styles.slide}>First Slide</div>
<div className={styles.slide}>Second Slide</div>
<div className={styles.slide}>Third Slide</div>
<div className={styles.slide}>Fourth Slide</div>
<div className={styles.slide}>Fifth Slide</div>
</Slide>
<div>
<Button type="button" onClick={back}>
Back
</Button>
<Button type="button" onClick={next}>
Next
</Button>
<select className={styles.select} onChange={goto}>
<option>--Select--</option>
{options}
</select>
</div>
</div>
);

Why don´´t work onClick on option element

I'm developing a plugin to search streets with elastic search, ok?
I have a datalist to show my options to select.
When I receive info from database I create all html option elemtns and add click event to capture and handle.
But I dont know why not works onClick event that I've added to each option element.
Here is my code EDITED:
render() {
const { value, streets, error, labelError } = this.state;
return (
<div className="w-100 d-flex flex-column">
<div className="plug-search plug-search__content">
<div className="plug-inner-addon">
<input onKeyDown={this.handlePressEnter.bind(this)} onChange={this.handleSearch.bind(this)} type="text" placeholder={PLACEHOLDER} value={value} list="streets" autoComplete="on" />
<datalist id="streets">
{ streets && streets.length > 0 && streets.map((street, index) => {
return (
<Item street={street} position={index} key={index} />
);
})}
</datalist>
</div>
<div className="plug-btn-search plug-btn-search__content">
<i onClick={this.handleGetGeometry} className={`icon-search plug-search-icon`}></i>
</div>
</div>
{error &&
<div className={`plug-error plug-error__content ${(error) ? 'slideDown' : 'slideUp'}`}>
<label className="plug-label">{labelError}</label>
</div>
}
</div>
);
}
Now I've created a Item component, but still doesnt work:
class Item extends Component {
clickedOption = (event, index) => {
console.log('clicked');
console.log('value: ', event.target.value);
console.log('index: ', index);
};
render() {
return (
<div className="option" onClick={(event) => this.clickedOption(event, this.props.position)}>
<option value={this.props.street.nombre} />
</div>
)
}
}
export default Item;
Currently, <datalist /> don't support onClick events in his <options />, you could see this question, in order to apply an option in this kind of cases. Hope this help.
Thanks to Alberto Perez
Solved:
clickedOption = (event) => {
console.log('clicked');
console.log('value: ', event.target.value);
};
render() {
const { value, streets, error, labelError } = this.state;
return (
<div className="w-100 d-flex flex-column">
<div className="plug-search plug-search__content">
<div className="plug-inner-addon">
<input onInput={this.clickedOption} onChange={this.handleSearch.bind(this)} type="text" placeholder={PLACEHOLDER} value={value} list="streets" autoComplete="on" />
<datalist id="streets">
{ streets && streets.length > 0 && streets.map((street, index) => {
return (
<option value={street.nombre} key={index} />
);
})}
</datalist>
</div>
<div className="plug-btn-search plug-btn-search__content">
<i onClick={this.handleGetGeometry} className={`icon-search plug-search-icon`}></i>
</div>
</div>
{error &&
<div className={`plug-error plug-error__content ${(error) ? 'slideDown' : 'slideUp'}`}>
<label className="plug-label">{labelError}</label>
</div>
}
</div>
);
}
handleSearch = (e) => {
this.setState({
value: e.target.value
})
}
render() {
const { value, streets, error, labelError } = this.state;
return (
<div className="w-100 d-flex flex-column">
<div className="plug-search plug-search__content">
<div className="plug-inner-addon">
<input onKeyDown={this.handlePressEnter.bind(this)} onChange={this.handleSearch.bind(this)} type="text" placeholder={"placeholder"} value={value} list="streets" autoComplete="on" />
<datalist id="streets">
{ streets && streets.length > 0 && streets.map((street, index) => {
return (
<div key={index} className="option">
<option value={street.nombre} />
</div>
);
})}
</datalist>
</div>
<div className="plug-btn-search plug-btn-search__content">
<i onClick={this.handleGetGeometry} className={`icon-search plug-search-icon`}></i>
</div>
</div>
{error &&
<div className={`plug-error plug-error__content ${(error) ? 'slideDown' : 'slideUp' }`}>
<label className="plug-label">{labelError}</label>
</div>
}
</div>
);
}

Use image as icon with react-select

I would like to add an image as Icon with react-select. I did all right but I have a problem with the fact that, in react, images are written like this :
<img src={require(...)} />
So I use react-select like this :
const IconOption = (props) => (
<Option {... props}>
<div>
<img src={require(props.data.image)} />
</div>
</Option>
);
And then call for the select box :
render() {
return (
<Select
classNamePrefix="react-select"
placeholder={"Search..."}
onChange={this.handleChange}
components={{ DropdownIndicator: () => null, Option: IconOption }}
options={this.state.options}
openMenuOnClick={false}
styles={customStyle}
/>
);
}
I tried to write :
const IconOption = (props) => (
<Option {... props}>
<div>
{props.data.image}
</div>
</Option>
);
Which gives me :
./css/img/PROFILEPICTURE.jpg
It is exactly what I want to get, the path is correct. If I exactly write :
const IconOption = (props) => (
<Option {... props}>
<div>
<img src="./css/img/PROFILEPICTURE.jpg" />
</div>
</Option>
);
Image is correctly displayed.
If I write the first code, which is the one to get different picture for each item in selectbox, I got an error :
Any solution to not use require function for img in react?
Edit :
I also tried :
const IconOption = (props) =>
(
<Option {... props}>
<div>
<img src={props.data.image} />
{props.data.label}
</div>
</Option>
);
And i got not found images :
You just have to remove the require since your image is not part of the compiled react app:
const IconOption = (props) => (
<Option {... props}>
<div>
<img src={props.data.image} />
</div>
</Option>
);

React having onClick work only once on a component

Hello I am trying to build a forum site. I have simple categories and comments. I have a button that displays a text box to enter a comment on a category, but when I click the button it opens text boxes on every category. I just want one text box. Here is the code I have so far. Any help would be appreciated. Thanks
state = { showing: true };
renderLists(categories) {
const { showing } = this.state;
if (categories == null) return <div />;
return (
<ul className="ul">
{categories.map(category => {
return (
<li id={category._id} className="categories" key={category._id}>
{category.name}
<Posts categ={category._id} />
<button
className="label"
onClick={() => this.setState({ showing: !showing })}
>
Add Comment
</button>
{showing ? (
<div>
<form method="post" action="/post/create-posts">
<input type="text" name="body" />
<input type="hidden" name="cat" value={category._id} />
<input type="submit" value="Submit" />
</form>
</div>
) : null}
</li>
);
})}
</ul>
);
}
render() {
return (
<div>
<main className="categories">
{this.renderLists(this.state.category)}
</main>
</div>
);
}
Since you are controlling render of the form with a single state value, ever form for every item renders the form when the state value changes.
You should set a unique value on state to show single form every time.
Saving currently active items id to state and checking if that item is active or not can be a simple solution. This also ensures to only single form to be active. If you need to enable multiple forms to be active, you can change below code to hold an array of ids and checking if the id exist in array or not. This implementation also requires you to remove the id from array on a second click to remove form for that item.
Sample
state = { showing: ''};
renderLists(categories) {
const { showing } = this.state;
if (categories == null) return <div />;
return (
<ul className="ul">
{categories.map(category => {
return (
<li id={category._id} className="categories" key={category._id}>
{category.name}
<Posts categ={category._id} />
<button
className="label"
{/* Save item's id to state */}
onClick={() => this.setState({ showing: category._id })}
>
Add Comment
</button>
{/* check item's id */}
{(showing === category._id) ? (
<div>
<form method="post" action="/post/create-posts">
<input type="text" name="body" />
<input type="hidden" name="cat" value={category._id} />
<input type="submit" value="Submit" />
</form>
</div>
) : null}
</li>
);
})}
</ul>
);
}
You can set the dynamic state for each of your category. I have made it below. Initially it was not there in state. On clicking the button, it will update the state with new key(such as categoryName) as true. I have fixed it as toggle. If the required key is true then it will become false.
item.state = { showing: true };
renderLists(categories) {
const { showing } = this.state;
if (categories == null) return <div />;
return (
<ul className="ul">
{categories.map(category => {
let categoryName = category.name // get the categoryName in variable
return (
<li id={category._id} className="categories" key={category._id}>
{category.name}
<Posts categ={category._id} />
//You can also access the object values by using bracket ([]) notation. You can set the dynamic state with unique key, may be we use name as key here
<button
className="label"
onClick={() => {(this.state[categoryName] != undefined) ? (this.state[categoryName] ? this.setState({ [categoryName]: false }) : this.setState({ [categoryName]: true })) : this.setState({ [categoryName]: true })} }
>
Add Comment
</button>
{this.state[categoryName] ? (
<div>
<form method="post" action="/post/create-posts">
<input type="text" name="body" />
<input type="hidden" name="cat" value={category._id} />
<input type="submit" value="Submit" />
</form>
</div>
) : null}
</li>
);
})}
</ul>
);
}
render() {
return (
<div>
<main className="categories">
{this.renderLists(this.state.category)}
</main>
</div>
);
}

Resources