React Select palceholder does show up but with some erros. So below is the source code from my project where on click of a button, a modal is displayed where the users are allowed to fill the form. here the drop down list is being displayed where the placeholder for the drop down is not being displayed.
Object
getCountries()
[
{"id":"a6cedb32","name":"America","code":"USA"},
{"id":"042aa7bd0f","name":"Yemen","code":"YE"}
]
useEffect(() => {
if(countryList)
{
let countryDDL = countryList?.map(obj => ({
...obj,
label: obj.code
}))
setCountryDDL(countryDDL)
}
}, [countryList])
return (
<div>
<Select
options={countryDDL}
name="country"
placeholder="I ain't showing up"
/>
</div>
)
}
export function validationSchema() {
return Yup.object({
country: Yup.string().required("This field is required")
});
}
Your obj does not have any code, I'm not sure what are you trying to provide as a value.
Also obj??.code will result an error.
And obj array missing to ','
const obj = [
{ "id":"a654d086",
"label":"A" // here
"name":"A"
},
{
"id":"a654d656086",
"label":"B" //and here
"name":"B"
}
]
Your problem is not in placeholder at all. Your select can't work with provided data. Try something like this:
const [selectedObj, setSelectedObj] = useState();
const handleSelect = (value) => {
setSelectedObj(value)
}
<Select
options={obj}
value={{label: selectedObj.name}}
name="name"
onSelect={handleSelect}
placeholder="Please show up"
/>
This probably might not run, I haven't test it, but the main idea is here. You should select some object from your array of objects (named obj) and display its' value. Currently you are trying to pass name from obj itself and it doesn't have such property at all
Related
I have created a list of objects and each list item has input within:
{flowers_data?.map((flower) => {
return (
<>
<div className={classes.Nested_Flower_Container} key={flower.id}>
<div className={classes.Nested_Flower_Name}>
{flower.name}
</div>
<div className={classes.Nested_Flower_Input} style={{ marginRight: '0.2em' }}>
<TextField
id="Amount"
label="Amount"
variant="outlined"
size="small"
type="number"
onChange={(e) => {
setAmount(e.target.value);
handleAddList(e.target.value, flower);
}}
className={classes_2.root}
/>
</div>
</div>
</>)
})}
How can I add an object that has a value in input to an array? I tried to do this using a function that I created, but each time I change one element's target.value and move on to the next item to change its input value, there is only one element in the array with the latest target.value. And after modifying the inputs, when I try to output the values outside that function with e.g. a button, the add_flowers_tab array is empty.
handleAddList function:
let temp_flower: Flower;
let add_flowers_tab: Flower[] = [];
const handleAddList = (targetValue: string, flower: Flower) => {
temp_flower = {
"id": flower.id,
"name": flower.name,
"price": flower.price,
"amount": Number(targetValue),
"creation_date": flower.creation_date
}
if (targetValue === '') {
/* Delete flower when input is empty */
add_flowers_tab.forEach(tabFlower => {
if (tabFlower.id === temp_flower.id) {
const indexOfDelete = add_flowers_tab.indexOf(tabFlower);
add_flowers_tab.splice(indexOfDelete, 1);
}
})
}
if (targetValue !== '') {
/* Add flower to tab when input has value */
if (add_flowers_tab.length > 0) {
/* When input changes, delete flower with old input value and add the new one */
add_flowers_tab.forEach(tabFlower => {
if (tabFlower.id === temp_flower.id) {
const indexOfDelete = add_flowers_tab.indexOf(tabFlower);
add_flowers_tab.splice(indexOfDelete, 1);
add_flowers_tab.push(temp_flower);
}
})
}
else {
/* Add new flower as a first element in the array */
add_flowers_tab.push(temp_flower);
}
/*
Displays an array with only the most recently added temp_flower, even though
several inputs in list have values
*/
console.log(add_flowers_tab);
}
}
Here is the minimum solution for generating a list on Inputs that each update a single element in a list on state.
export const ManyInputs = ({inputs}) => {
const [list, setList] = useState(inputs);
const setIndividual = (value, id) =>
// Update a single field in the object in the list that matches the given id
setList(list.map(l => l.id === id ? ({...l, value}) : l));
return list.map(i =>
// Send the id back to help match the object
<TextField onChange={(e) => setIndividual(e.target.value, i.id)} />
);
};
You can have one React state, which has an array of objects that you enter through your "mapped" component.
const [tmpAmount, setTmpAmount] = React.useState<{flower:Flower,amount:number}[]>([])
// fill the temporary state with generated flowers only once
React.useEffect(()=>{
setTmpAmount(flowers_data.map((flwr) =>{flower:flwr, amount:0}))
},[])
and replace the onChange()
onChange={(e) => {
// find existing flower to edit the amount of it
let indexToChange = flowers_data.findIndex((element) => element.id === flower.id)
// update and replace the array variable with updated object
setAmount2((prev) =>
[
...prev.slice(0, indexToChange),
{
...prev[indexToChange],
amount: e.target.value,
},
...prev.slice(indexToChange + 1),
]);
}
You can also check if the array changes and print it:
React.useEffect(()=>console.log(tmpAmount),[tmpAmount])
I have a React component that renders an array with an input field and a radio button. The input field is working fine but when clicking the radio button even though the state gets updated, the value is not reflected in the UI.
Following is the implementation of the React component
import React, { useState } from 'react';
import './style.css';
export default function App() {
const [subTemplate, setSubTemplate] = useState([
{ name: 'main', outputFormat: 'html' },
{ name: 'something else', outputFormat: 'text' }
]);
const handleInputChange = (value, row, key) => {
const updatedSubTemplate = subTemplate.map(item => {
if (item.name === row.name) {
return {
...item,
[key]: value
};
}
return item;
});
console.log('updatedSubTemplate', updatedSubTemplate); // updatedSubTemplate consists of the modified value
setSubTemplate(updatedSubTemplate);
};
const renderSubTemplates = () => {
return subTemplate.map((item, index) => {
return (
<div key={index}>
<input
type="text"
value={item.name}
onChange={e => {
handleInputChange(e.target.value, item, 'name');
}}
/>
<div>
<input
type="radio"
name="html"
checked={item.outputFormat === 'html'}
onChange={e => {
handleInputChange(e.target.name, item, 'outputFormat');
}}
/>
HTML
</div>
<div>
<input
type="radio"
name="text"
checked={item.outputFormat === 'text'}
onChange={e => {
handleInputChange(e.target.name, item, 'outputFormat');
}}
/>
TEXT
</div>
</div>
);
});
};
return <div>{renderSubTemplates()}</div>;
}
Following is a stackblitz link for the above implementation : https://stackblitz.com/edit/react-ugat24
Note: The radio button works as expected if there's only 1 element in the array.
It is because you have different value in name attribute.
Radio buttons are used to select one option from a list of options. so they need to have the same name to group them .
<input
type="radio"
name={`group-${index}`}
checked={item.outputFormat === 'html'}
onChange={e => {
handleInputChange('html', item, 'outputFormat');
}}
/>
Working Sample
https://stackblitz.com/edit/react-4xxpev
There are 2 issues in your code.
You are passing the same name attribute for all the radio inputs.
You are passing the wrong value for the radio elements.
Use template literals to append the index value to each set of radio group elements in the array.
Here's working code
References
Radio Input
Template literals
So I have a state:
const [persons, setPersons] = useState([{ id: 1, name: "Arto Hellas" }]);
const [newName, setNewName] = useState("");
A simple form:
<form onSubmit={addName}>
<div>
name: <input value={newName} onChange={handleNameChange} />
</div>
<div>
<button type="submit">add</button>
</div>
</form>
And the handlers for the form. I can add new names and render them but
Im trying to check if the name typed in the input has allready been added and if so just a simple alert that its not possible. I have banged my head in the wall for hours trying everything I could but with my knowledge it just isnt going anywhere. (Starter exercises for open uni at my country)
All you need to do is find the element in persons, If it is present then alert, console.log, or tell the user that it is not possible else add into the state.
demo
I've used console.log, You can use alert or anything to tell the user.
function addName(e) {
e.preventDefault();
const isPresent = persons.find((p) => p.name === newName);
if (!isPresent) {
setPersons((state) => {
return [...state, { id: state.length + 1, name: newName }];
});
setNewName(""); // Clear the input
} else {
console.log("Not possible");
}
}
I have this kind of objects
{
asignaturaId: 1,
content: {
[question_var]: {
elements: {
text: 'text1',
image: 'img1.jpg'
}
}
[question_var]: {
text: 'text2',
image: 'image2.jpg'
}
}
}
the thing that varies is the [question_var] part and how many objects does content key includes.
I want to be able to dynamically write out all the data on inputs and being able to replace the needed data.
so far I got this:
[...]
<FormControl>
<InputLabel htmlFor="modulo">Asignatura ID:</InputLabel>
<Input id="asignaturaId" name="asignaturaId" value={arrayData[0]} onChange={(e) => setAsignaturaId(e.target.value)} />
</FormControl>
{arrayData.map(pregunta => {
console.log(pregunta)
return (
<>
<FormControl>
<InputLabel htmlFor="texto">Texto:</InputLabel>
<Input id="texto" name="texto" onLoad={() => setTexto(pregunta[1].elements.text)} value={pregunta[1].elements} onChange={(e) => setText(e.target.value)} />
</FormControl>
[...]
what I omited was, I took the object and did Object.entries(myObject) and assigned it to the arrayData array. asignaturaId will be just one key on every object I receive, so I can easily pass that value and change it on an input. The problem is the content, as it is dynamic and change too much, I find it hard to use useEffect() hook to populate my input with the data I receive and manipulating it in the same input without changing the other values with the same keys or straight foward, not being able to edit them at all.
I have 4 days in this problem. please help!
Edit: I am sorry about my english, if I didn't make myself clear, I want to overwrite the object, keeping the data the user doesn't update in the front end.
Declear your json array first in your React hook Component and make sure each object should have unique key
const [yourJson,setYourJson] = useState({
asignaturaId: 1,
content: {
[question_var1]: {
elements: {
text: 'text1',
image: 'img1.jpg'
}
},
[question_var2]: {
text: 'text2',
image: 'image2.jpg'
}
}
});
Add Setter to add new object in your json content
const addNewData = (text, imgSrc) =>{
let newIndex = Object.keys(yourJson.content).length + 1;
let newJson = yourJson;
newJson.content[`question_var${newIndex}`] = {
'text': text,
'image': imgSrc
}
setYourJson({...newJson})
}
And in render callback use this mapping
<FormControl>
{Object.keys(yourJson.content).map(key => (
<InputLabel htmlFor="texto">{yourJson.content[key].text}</InputLabel>
// <Input id="texto" name="texto" ....
))}
</FormControl>
So what i need to do is have the search form of react-select not only react to id an value, but i also want it to be able to search for synonyms of the select options.
For example in a unit of measures list:
{
"id": "MIN",
"name": "minute",
"synonym": "time"
}
I want to be able to type in "min", "minute" or "time" and end up with the selection "minute".
I tried it with pushing another element into the array:
mapUnitOfMeasure()
{
const results = [ ];
for(const c of measureUnits)
results.push({ value : c.id, label : c.name, syn: c.synonym });
}
return results
}
In my render method, the select element looks like this:
<Select
className="react-select"
placeholder=""
disabled={this.state.disabled}
value={this.state.value}
onChange={this.handleChange.bind(this)}
onBlur={this.handleBlur.bind(this)}
searchable={true}
clearable={true}
multi={false}
noResultsText={i18n.getMessage('CurrencyInput.search.form.noResults')}
options={this.mapUnitOfMeasure()} />
)
But "syn" never reacts to a search query.
Anyone have an idea how i can make it work?
I suggest you to use filterOptions props that allows you to create your own filter function.
By default it works like this:
filterOptions={(options, filter, currentValues) => {
// Do no filtering, just return all options
return options;
}}
If you want to make a search in label and syn you can use the function like this:
filterOptions = (options, filterString, values) => {
return options.filter(
x => x.synonym.includes(filterString) || x.label.includes(filterString)
);
};
WARNING
Using filterOptions will override filterOption, matchPos, matchProp, ignoreCase and ignoreAccents options. You will have to take care of those props by yourself.
Here a live example.