ReactJS: Sort Option choices from API - javascript

I have a select and it gets the options from the api, and it looks like this:
I want to sort them in ascending form but I don't know how to do that, here is my code
<select className="form-control form-control-sm" name="subscriptions" onChange={this.changeValues}>
{
this.state.variantsData.subscription_plans.map((item, i) => <option key={i} value={item.uuid}>{item.name}</option>)
}
</select>

You could write a function that sorts your data which you can then render. To optimise it further you can memoize this function
sortData = (array) => {
return array.sort(function(a, b) {
a.match(/(\d+) months/i)[1] - b.match(/(\d+) months/i)[1]
})
}
render() {
const data = this.sortData(this.state.variantsData.subscription_plan);
return (
<select className="form-control form-control-sm" name="subscriptions" onChange={this.changeValues}>
{this.state.variantsData.subscription_plans.map((item, i) => (
<option key={i} value={item.uuid}>{item.name}</option>
))
}
</select>
)
}

Related

How to wait for options of a select element

I want to select the option in the select element after all the options are drawn using a map method. I don't want to use setTimeout to wait for a while. I want to know after all the options are rendered.
The select is in a pop up modal which is shown after a button is clicked.
<select
ref={classSelRef}
className="form-select mr-sm-2"
id="class"
required
onChange={e => setClassId(e.target.value)}>
{classes.map(c => {
return (
<option key={c.id} value={c.id}>
{c.class_name}
</option>
)
})}
</select>
And here is the option selection method.
const selectOption = (ele, value) => {
return [...ele.options].some((option, index) => {
if (option.value === value) {
ele.selectedIndex = index
return true
}
})
}
You can add logical operator && before map function like so
<select
ref={classSelRef}
className="form-select mr-sm-2"
id="class"
required
onChange={e => setClassId(e.target.value)}>
{classes && classes.map(c => {
return (
<option key={c.id} value={c.id}>
{c.class_name}
</option>
)
})}
This will wait classes to be true before map is executed

Javascript / React - How to update the values of a multidimensional array with the values of a `select` input inside of a forEach loop?

I'm trying to update the values of a multidimensional array with the values of a select input inside of a forEach loop. It's one array that holds two inner arrays. Every time I change the values with the select input, both inner arrays get updated. How can I get the inner arrays to update individually?
codesandbox - https://codesandbox.io/s/multidimensional-array-3v6pmi
Update the state fxChoices considering it as a multi-dimentional array. Please refer the code-sandbox here.
Try to set the state as the value of each drop-down. Don't use the drop-down only to change the state, but use it to view the actual state that you've set.
Organize your component like below. Now it's just a matter of changing NUMER_OF_INPUTS as many inputs you want.
const NUMER_OF_INPUTS = 2;
function App() {
const [fxChoices, setFxChoices] = React.useState(
Array.from({ length: NUMER_OF_INPUTS }).map(() => [[]])
);
console.log("fxChoices", fxChoices);
const onChangeHandler = (compIndex, optionIndex, option) => {
setFxChoices((prevState) =>
prevState.map((item, itemIndex) => {
if (itemIndex === compIndex) {
const copyItem = [...item];
copyItem[optionIndex] = option;
return copyItem;
}
return item;
})
);
};
return (
<div className="App">
{Array.from({ length: NUMER_OF_INPUTS }).map((_, j) => {
return (
<div key={j}>
<p>bus{j + 1}</p>
<SelectComponent compIndex={j} onChangeHandler={onChangeHandler} />
</div>
);
})}
</div>
);
}
const SelectComponent = ({ onChangeHandler, compIndex }) => {
return Array.from({ length: 2 }).map((_, i) => (
<div key={i} style={{ display: "flex", flexDirection: "column" }}>
<select
onChange={(e) => {
onChangeHandler(compIndex, i, e.target.value);
}}
className="effect-select"
>
<option value={`bs${i + 1}-fx${i + 1}`}>{`FX${i + 1}`}</option>
<option value="reverb">Reverb</option>
<option value="delay">Delay</option>
<option value="chorus">Chorus</option>
<option value="chebyshev">Chebyshev</option>
<option value="pitch-shift">PitchShift</option>
<option value="compressor">Compressor</option>
</select>
</div>
));
};
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>
NOTE: Try to think like building boxes when designing components.
Maybe it is easier to map you multidimensionnal array to access the indexes easily like below
import { useState } from "react";
import "./styles.css";
export default function App() {
const Options = () => {
const [fxChoices, setFxChoices] = useState([...Array(2)].map(() => [...Array(2)].map(() => null)));
console.log(fxChoices)
return (<>
{fxChoices.map((item, i) => (
<div key={i}>
<p>bus{i + 1}</p>
<div style={{ display: "flex", flexDirection: "column" }}>
{item.map((_, index) => <select
onChange={(e) => {
fxChoices[i][index] = e.target.value
setFxChoices(fxChoices);
console.log("fxChoices", fxChoices);
}}
className="effect-select"
>
<option value={`bs${i + 1}-fx${i + 1}`}>{`FX${i + 1}`}</option>
<option value="reverb">Reverb</option>
<option value="delay">Delay</option>
<option value="chorus">Chorus</option>
<option value="chebyshev">Chebyshev</option>
<option value="pitch-shift">PitchShift</option>
<option value="compressor">Compressor</option>
</select>)}
</div>
</div>
))
}
</>
);
};
return (
<div className="App">
<Options />
</div>
);
}

How can I do to show three params when I click on the select using react.js?

I have a select such as :
<Select id='1' list={[...this.state.dictionnary]}/>
where this.state.dictionnary is like this :
state = {
dictionnary: [
{value: "a", name: "ab"},
]}
And the component select is like this :
class Select extends Component {
handleChange()
{
// I would like to show 1, a and ab
// 1 is the id of the select
// a and ab are value and name of
};
render() {
return (
<select onChange={this.handleChange} className="custom-select">{this.props.list.map(option => (
<option key={option.value} value={option.value}>{option.name}</option>))}
</select>
)
}
}
export default Select;
I would like to show some informations using the handleChange() function like the id, name and value.
Could you help me please ?
Thank you very much
You should change the option so the value has the entire object to get it later in the handleChange. Also, to access the same this with the props in the handleChange method you need to use an arrow function:
<select onChange={(e) => this.handleChange} className="custom-select">
{this.props.list.map((option) => (
<option key={option.value} value={option}>
{option.name}
</option>
))}
</select>
By default, the onChange handler gets the event param so you can get the target and the props:
handleChange(event) {
const { value, name } = event.target.value;
console.log(this.props.id, value, name);
}
Adding to #Alavaro answer, you need to split after getting the value to remote ,
handleChange = e => {
const [value, name] = e.target.value.split(',')
console.log({ id: this.props.id, value, name})
}
render() {
return (
<select onChange={this.handleChange} className="custom-select">
{this.props.list.map((option, index) => (
<option key={option.value} value={[option.value, option.name]} >
{ option.name }
</option>
))}
</select>
);
}
}

How to get data from cloud firestore then filter it, map it then return it?

I am trying to get data from the firestore and then filter it then map it like so:
return Inventory
.filter(x =>x["sub_category"] === item && x["category"] === category)
.map(({id, item, price, quantity, image})=>{
//sets the default value for the item with that specific id
const defVal = parseInt((selectedQty.id === id)?selectedQty.qty:0)
return (
<React.Fragment key={uuid()}>
<div className="card">
<img src={image()} alt={item} />
<p>{item}</p>
<div className="innerBox">
<div className="dropdown">
<label htmlFor="quantity">Qty:</label>
<select id="quantity" defaultValue={defVal===0?1:defVal} onChange={e => {
e.preventDefault()
setSelectedQty({id, qty: parseInt(e.target.value)})
}}>
{
Array(quantity).fill().map((_, i)=> {
if(i===0){
return <option key={uuid()} value={0}>-</option>
}else{
return <option key={uuid()} value={i} >{i}</option>
}
})
}
</select>
</div>
<b>$ {price}</b>
</div>
<button type="submit" onClick={()=> {
addToCart(id, item, parseInt(finalQty), price, image(), parseInt(finalQty)*parseFloat(price))
setSelectedQty({id:null, qty: 0})
}}>Add to Cart</button>
</div>
</React.Fragment>
)})
Currently I am using Inventory Array but I want to switch to firestore but I have no clue how to do it. I am aware of the step db.collection().get().then(etc...) but i don't know how to map it to return it inside the Then
When you fetch data from cloud firestore, it returns a document / collection snapshot.
Document:
db.collection("colName").doc("docID").get().then(docSnapShot=>{
const docID = docSnapShot.id;
const docData = docSnapShot.data();
})
Collection:
db.collection("colName").get().then(colSnapShot=>{
const isEmpty = colSnapShot.empty;
const docsData = colSnapShot.docs.forEach(docSnapShot=>{
return docSnapShot.data();
})
})
I believe your solution will look something like this:
let arrOfDocs = await db.collection("colName").get().then(colSnapShot=>{
return colSnapShot.docs.map(docSnapShot=>{
return docSnapShot.data();
})
})
Note that to listen to live updates, replace get().then(snapshot=>{}) with onSnapshot(snapshot=>{})

Update a select's options based on another dropdown, using React

I've got 2 selects in my form. Options for the 2nd select are generated based on 1st select. Everything works fine except that every time I choose an option for the 2nd select and then change the 1st one, I should get the default option for the 2nd, but it's not resetting.
Code below
const [animalClass, setAnimalClass] = useState();
const [animalType, setAnimalType] = useState();
const [isLoadingClasses, setLoadingClasses] = useState(true);
const [isLoadingTypes, setLoadingTypes] = useState(true);
const [availableAnimalClasses, setAvailableAnimalClasses] = useState();
const [availableAnimalTypes, setAvailableAnimalTypes] = useState();
useEffect(() => {
setLoadingClasses(true);
const availableOptions = async () => {
const availableClasses = await Axios.get();
console.log(availableClasses.data);
if (availableClasses.data.length > 0) {
setAvailableAnimalClasses(availableClasses.data.map(animal => ({name: animal.name})));
setLoadingClasses(false);
}
};
availableOptions();
}, []);
useEffect(() => {
setLoadingTypes(true);
setAnimalType("DEFAULT");
const availableOptions = async () => {
const availableTypes = await Axios.get();
console.log(availableTypes.data);
if(availableTypes.data.length > 0) {
setAvailableAnimalTypes(availableTypes.data.map(animal => ({name: animal.name})));
setLoadingTypes(false);
}
};
availableOptions();
}, [animalClass]);
return (
<div className="page">
<h2>New Auction</h2>
<form className="form" onSubmit={onSubmit}>
<label>
Animal Class
<select defaultValue={'DEFAULT'} onChange={(e) => setAnimalClass(e.target.value)} >
<option value="DEFAULT" disabled>Choose animal class</option>
{isLoadingClasses ? <option value="Loading" disabled>Loading.....</option> : availableAnimalClasses.map((option) => (
<option value={option.name}>{upperCase(option.name)}</option>
))}
</select>
</label>
<label>Animal Type
<select defaultValue={'DEFAULT'} onChange={(e) => setAnimalType(e.target.value)} >
<option value="DEFAULT" disabled>Choose animal type</option>
{isLoadingTypes? <option value="Loading" disabled>Loading.....</option> : availableAnimalTypes.map((option) => (
<option value={option.name}>{upperCase(option.name)}</option>
))}
</select>
Since you are using state to store your form field values, you could set your defaults when you create the hooks:
const [animalClass, setAnimalClass] = useState('DEFAULT');
const [animalType, setAnimalType] = useState('DEFAULT');
and then use value instead of defaultValue in your JSX:
<select value={animalClass} onChange={(e) => setAnimalClass(e.target.value)} >
...
<select value={animalType} onChange={(e) => setAnimalType(e.target.value)} >
These values should reset your select elements when the state changes.
You should call setAnimalType to reset it back to the default when selecting the animal class. Change:
<select defaultValue={'DEFAULT'} onChange={(e) => setAnimalClass(e.target.value)}>...</select>
...to:
<label>
Animal Class
<select
defaultValue={'DEFAULT'}
value={animalClass}
onChange={(e) => {
setAnimalClass(e.target.value);
setAnimalType('DEFAULT');
}}
>
...
</select>
</label>
<label>
Animal Type
<select
defaultValue={'DEFAULT'}
value={animalType}
onChange={(e) => setAnimalType(e.target.value)}
>
// ...
</select>
</label>
This is necessary because the onChange event will not be automatically fired for a select when the options change. In order for this to work, where state controls the state of your <select/>s, you'll also want to change the defaultValueprops tovalue` props.

Categories

Resources