I am facing an issue with representing data inside select-react Component, I had successfully getting data form server side (node js ) by componentDidMount()
componentDidMount(){
fetch('api/transporationTypes')
.then( res => res.json())
.then(trasnportation => this.setState({trasnportation }, () => console.log(trasnportation)));
}
but I cannot set loaded data inside React-Select Component I tried the below here below how this component works with static data.
render() {
const { selectedOption } = this.state;
return (
<Select
name="form-field-name"
value={selectedOption}
onChange={this.handleChange}
options={[
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two' },
]}
/>
);
}
}
but when I trying to load dynamic data with code below it represent No results Found see screenshot: http://prntscr.com/jqvp76.
alos printing the data via console.log('optionItems',optionItems) in dev tools print correctly http://prntscr.com/jqvq7v
How can I make option of select component works successfully
render() {
const { selectedOption } = this.state.selectedOption;
let optionItems = this.state.trasnportation.map((trans) =>
[ {value: `${trans.TransportationType}` , label : `${trans.TransportationType}`}]
);
console.log('optionItems',optionItems)
return (
<div className="row">
<h1>Choose Tranportation Type</h1>
<Select className="col-md-8"
name="form-field-name"
value={selectedOption}
onChange={this.handleChange1}
option={optionItems}
placeholder = "Select one of below"/>
</div>
);
}
}
Thanks -- Fadi
The items have wrong type:
let optionItems = this.state.trasnportation.map((trans) =>
[ {value: `${trans.TransportationType}` , label : `${trans.TransportationType}`}]
);
to
let optionItems = this.state.trasnportation.map((trans) =>
({value: `${trans.TransportationType}` , label : `${trans.TransportationType}`})
); // [] -> ()
It likely has something to do with the typos, in the code supplied there is:
trasnportation
transporation
transportation
Related
I am trying to keep track of which boxes are checked in my local state(you can check multiple boxes). I want to be able to check and uncheck the boxes and keep track of the ids of the boxes that are checked. I will do something with the values later. This is what I have so far:
import React, { Component } from 'react'
import './App.css'
import CheckBox from './CheckBox'
class App extends Component {
constructor(props) {
super(props)
this.state = {
fruits: [
{id: 1, value: "banana", isChecked: false},
{id: 2, value: "apple", isChecked: false},
{id: 3, value: "mango", isChecked: false},
{id: 4, value: "grape", isChecked: false}
],
fruitIds: []
}
}
handleCheckChildElement = (e) => {
const index = this.state.fruits.findIndex((fruit) => fruit.value === e.target.value),
fruits = [...this.state.fruits],
checkedOrNot = e.target.checked === true ? true : false;
fruits[index] = {id: fruits[index].id, value: fruits[index].value, isChecked: checkedOrNot};
this.setState({fruits});
this.updateCheckedIds(e);
}
updateCheckedIds = (e) => {
const fruitIds = [...this.state.fruitIds],
updatedFruitIds= fruitIds.concat(e.target.id);
this.setState({updatedFruitIds});
}
render() {
const { fruits } = this.state;
if (!fruits) return;
const fruitOptions = fruits.map((fruit, index) => {
return (
<CheckBox key={index}
handleCheckChildElement={this.handleCheckChildElement}
isChecked={fruit.isChecked}
id={fruit.id}
value={fruit.value}
/>
);
})
return (
<div className="App">
<h1>Choose one or more fruits</h1>
<ul>
{ fruitOptions }
</ul>
</div>
);
}
}
export default App
So basically I am able to check and uncheck the boxes, but I cannot seem to update and store the fruitIds. Here is my checkbox component also:
import React from 'react'
export const CheckBox = props => {
return (
<li>
<input key={props.id}
onChange={props.handleCheckChildElement}
type="checkbox"
id={props.id}
checked={props.isChecked}
value={props.value}
/>
{props.value}
</li>
)
}
export default CheckBox
Also if you have a cleaner ways to do this than the way I am doing it, I would love to see it.
This is what if I were to approach it I will do. I will create a one dimensional array that holds the id's of the fruits when A fruit if clicked(checked) I will add it id to the array and when its clicked the second time I check if the array already has the id I remove it. then the presence of id in the array will mean the fruit is checked otherwise its not checked So I will do something like below
this.state={
fruitsIds: []
}
handleCheckChildElement=(id) => {
//the logic here is to remove the id if its already exist else add it. and set it back to state
const fruitsIds = this.state.fruitsIds;
this.setState({fruitsIds: fruitsIds.contains(id) ? fruitsIds.filter(i => i != id) : [...fruitsIds, id] })
}
then I render the checkboxes like
<CheckBox key={index}
handleCheckChildElement={this.handleCheckChildElement}
isChecked = { this.state.fruitsIds.contains(fruit.id)}
id={fruit.id}
/>
This is because you can always use the id to get all the other properties of the fruit so there is absolutely no need storing them again.
then the checkbox component should be as follows
export const CheckBox = props => {
return (
<li>
<input key={props.id}
onChange={() => props.handleCheckChildElement(props.id)}
type="checkbox"
id={props.id}
checked={props.isChecked}
value={props.value}
/>
{props.value}
</li>
)
}
The reason you are not getting your ids updated because:
You are trying to concat a non array element to an array.
concat is used for joining two or more arrays.
updatedFruitIds = fruitIds.concat(e.target.id);
You are not updating your actual fruitIds state field. I dont know why you are using "updatedFruitIds" this variable but due to above error it will always result into a single element array.
this.setState({ updatedFruitIds });
updateCheckedIds = e => {
const fruitIds = [...this.state.fruitIds],
updatedFruitIds = fruitIds.concat([e.target.id]);
this.setState({ fruitIds: updatedFruitIds });
};
OR
updateCheckedIds = e => {
const fruitIds = [...this.state.fruitIds, e.target.id],
this.setState({ fruitIds });
};
I am working with react and I have a dropdown menu which is generated like that:
Select a user : <select defaultValue={'DEFAULT'} onChange={this.handleFilter}><option value="DEFAULT" disabled>-- select an gangster --</option>{ddUsers}</select>
ddUsers:
let ddUsers = this.state.users.map(user => <option key={uuid.v4()} value={user}>{user.name}</option>)
And here is my users array:
users : [
{ name: 'All', key : uuid.v4()},
{ name: 'Koko', key : uuid.v4()},
{ name: 'Krikri', key : uuid.v4()},
{ name: 'Kéké', key : uuid.v4()}
]
My problem is that when I want to use the event.target it return me the entire select tag (here the output of console.log(event.target):
<select>
<option value="DEFAULT" disabled selected>-- select an gangster --</option>
<option value="[object Object]">All</option>
<option value="[object Object]">Koko</option>
<option value="[object Object]">Krikri</option>
<option value="[object Object]">Kéké</option>
</select>
where it should normally return me only the user.
here is my handleUser (which displays me select tag above):
handleFilter = (event) => {
console.log(event.target);
}
I am lost on what I am missing. I have something similar and it's working perfectly.
What you want is a key/value at select value, but unfortunately, it does not work.
Maybe you'll need to use another component like React-select or use JSON.stringfy() and JSON.parse()
I have made an abstraction code using JSON methods.
const uuid = {
v4() {
return Math.random();
}
};
const users = [
{ name: "All", key: uuid.v4() },
{ name: "Koko", key: uuid.v4() },
{ name: "Krikri", key: uuid.v4() },
{ name: "Kéké", key: uuid.v4() }
];
function App() {
const [selected, setSelected] = React.useState("");
function parseSelected(event) {
const valueToParse = event.target.value;
const itemSelected = JSON.parse(valueToParse);
setSelected(itemSelected);
return;
}
return (
<div>
<select name="any" id="any" onChange={parseSelected}>
{users.map(user => (
<option key={user.key} value={JSON.stringify(user)}>
{user.name}
</option>
))}
</select>
<p>Selected name: {selected.name}</p>
<p>Selected key: {selected.key}</p>
</div>
);
}
the reason is Option HTML interface accepts only DOMString as a value.
You can see the docs here
You could do something like this.. This allows for flexibility so you can use this <select> component anywhere, using any object with any property.. (using #CarlosQuerioz answer, you'd always have to use an object with a name key)
Parameter meanings:
data: array you are wanting to use as options for select
value: the key from your data property that you want to display
placeholder: placeholder value (not selectable)
defaultOption: default selected option (more on this below)
onSelectChange: event that is fired when selection changes
How we handle defaultOption:
If you pass in an array of objects to defaultOption we will select the first object in that array, and use the specified value key to determine the value to be shown
If you pass in an object, we will show the specified value key
To demonstrate the defaultOption, uncomment each of these values in the example below, you'll see what I mean.
const users = [ // If this was your `data` object
{ name: "Karkar", key: 1 },
{ name: "Koko", key: 2 },
{ name: "Krikri", key: 3 },
{ name: "Kéké", key: 4 }
];
<MySelect
data={users}
value="name" // Must be a valid key that your objects have
onSelectChange={handle}
defaultOption={users[0].name}
//defaultOption={users[1]} // Would display 'Koko' by default
//defaultOption={users} // Would display 'Karkar' by default
/>
EXAMPLE:
const { useState, useEffect } = React;
const { render } = ReactDOM;
function MySelect({ data, value, defaultOption = "", onSelectChange, placeholder = "Select an option" }) {
const [selected, setSelected] = useState(defaultOption);
const handleOnSelectChange = selection => {
onSelectChange && onSelectChange(selection);
}
const handleChange = event => {
let sel = data.find(d => d[value] === event.target.value);
setSelected(sel);
handleOnSelectChange(sel);
};
useEffect(() => {
if (typeof selected === "object") {
let val = selected.length > 0 ? selected[0] : selected;
setSelected(val);
handleOnSelectChange(val);
}
}, []);
return (
<select value={selected[value]} onChange={handleChange}>
<option value="" disabled>
{placeholder}
</option>
{data && data.map((itm, indx) => (
<option key={indx} value={itm[value]}>
{itm[value]}
</option>
))}
</select>
);
}
const users = [
{ name: "Karkar", key: 1 },
{ name: "Koko", key: 2 },
{ name: "Krikri", key: 3 },
{ name: "Kéké", key: 4 }
];
function App() {
const [user, setUser] = useState();
const handle = selectedUser => {
setUser(selectedUser);
};
return (
<div>
<MySelect
data={users}
value="name"
placeholder="Please make a selection"
onSelectChange={handle}
//defaultOption={users[0].name}
//defaultOption={users[0]}
defaultOption={users}
/>
{user && <pre>{JSON.stringify(user, null, 2)}</pre>}
</div>
);
}
render(<App />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.9.0/umd/react-dom.production.min.js"></script>
I am very beginning to reactJS and front end
I added react-select npm for my dropdown like below, before added react-select everything is working fine. How to define name in Select?
<div className="container">
<div className="row">
<div className="col-md-4" />
<div className="col-md-4">
<Select
options={this.state.allGenres}
onChange={this.props.onDataChange}
name="genre"
/>
</div>
<div className="col-md-4" />
</div>
</div>
this is my array,
var Data = response.data;
const map = Data.map((arrElement, index) => ({
label: arrElement,
value: index
}));
example:
[
{
"label": "Action",
"value": 0
},
{
"label": "Comedy",
"value": 1
},
{
"label": "Documentary",
"value": 2
}
]
error message coming in here,
dataChange(ev, action) {
this.setState({
[ev.target.name]: ev.target.value
});
}
render()
render() {
return (
<Movie
onPostData={this.postData.bind(this)}
onDataChange={this.dataChange.bind(this)}
/>
);
}
Error
Uncaught TypeError: Cannot read property 'name' of undefined
at Movies.dataChange
You expect the first argument in react-select´s onChange method to be an event object, but it isn't.
The first argument is the selected option (or options if you have isMulti set).
There is also a second argument which is an object with the following attributes:
action: The action which triggered the change
name: The name given to the Select component using the name prop.
So if you want to use the name:
onDataChange={(value, action) => {
this.setState({
[action.name]: value
})
}}
Reference in source code
I worked around this method and it worked.
handleSelectChange: function(name) {
return function(newValue) {
// perform change on this.state for name and newValue
}.bind(this);
},
render: function() {
return (
<div>
<Select ...attrs... onChange={this.handleSelectChange('first')} />
<Select ...attrs... onChange={this.handleSelectChange('second')} />
</div>);
}
This is how you can get the value(s) of the selected option(s) and the name of the input as well.
For more info, check this issue on Github.
handleChange = (selectedOptions, actionMeta) => {
const inputName = actionMeta.name;
let selectedValues;
if (Array.isArray(selectedOptions)) {
// An array containing values of the selected options (like: ["one", "two", "three"]
selectedValues = selectedOptions.map(option => option.value);
// OR, use this if you want the values of the selected options as a string separated by comma (like: "one,two,three")
selectedValues = selectedOptions.map(option => option.value).join(",");
} else {
// An array containing the selected option (like: ["one"])
selectedValues = [selectedOptions.value];
// OR, use this if you want the value of the selected option as a string (like: "one")
selectedValues = selectedOptions.value;
}
// Do whatever you want with the selected values
//..
this.setState({
[inputName]: selectedValues
});
}
<Select
name="genre"
options={this.state.allGenres}
onChange={this.handleChange}
/>
I want to make a pre selected options that cannot be deleted based on w. whether a client has been visited or no, here is what I want to achieve
const { clients } = this.props.clients;
const listOfClients =
clients !== null &&
clients.clients.map(client => ({
value: client._id,
label: client.company
? client.company
: client.lastname + " " + client.lastname,
last_visit: client.last_visit,
wilaya: client.wilaya,
visited: client.visited // true : false
}));
and that's how i render my select options
<Select
name="clients"
isMulti
value={this.state.clients}
onChange={e => this.onChange(e, "clients")}
isClearable={this.state.clients.some(client => !client.visited)}
options={listOfClients || []}
className="basic-multi-select"
classNamePrefix="select"
/>
and my state holds an array of clients as follows :
[{value: "5c0e784f0249ea83d88bddf3", label: "sarl medic", visited: true}]
if visited = true , then this selected option must be greyed out and cannot be deleted. I've looked up this example but i don't understand where i went wrong. Thank you :)
Your listOfClients options are missing the important isFixed, it should be the same value as visited if I understand your code correctly.
Also with multi select you will need to disable manually the remove function like the following code:
const listOfClients =
clients !== null &&
clients.map(client => ({
value: client._id,
label: client.company
? client.company
: client.lastname + " " + client.lastname,
last_visit: client.last_visit,
wilaya: client.wilaya,
visited: client.visited,
isFixed: client.visited // true : false
}));
class App extends Component {
constructor(props) {
super(props);
this.state = {
clients: []
};
}
onChange = (e, option) => {
if (option.removedValue && option.removedValue.isFixed) return;
this.setState({
clients: e
});
};
render() {
return (
<div className="App">
<Select
name="clients"
isMulti
value={this.state.clients}
onChange={this.onChange}
isClearable={!this.state.clients.some(client => client.visited)}
options={listOfClients || []}
className="basic-multi-select"
classNamePrefix="select"
styles={styles}
/>
</div>
);
}
}
Here a live example.
Hey guys im trying to create a autosuggestion in cooperation with redux-form. Im using the Creatable approach. I loading my options via an external API. The problem is, i need a extra field in every Option Object. {value: "test#gmx.de", label: "test#gmx.de", dn:"CN...." }. Is there a possibility to do so?
I typically add my own properties inside the callback for the API request, just before setting the options in the state. For example...
axios.get('/some/api/request')
.then(response => {
const options = response.data.map(item => {
// Add whatever custom properties you want here
return ({value: "test#gmx.de", label: "test#gmx.de", dn:"CN...." })
})
// set your options in the state to the new options constant from above
dispatch(change('formName', 'options', options))
Hope this helps!
//Handle change with either selectedOption
handleChange(selectedOption){
this.setState({ selectedOption })
if(this.props.onOptionSelect){
this.props.onOptionSelect(selectedOption.data)
}
}
loadOptions(input, callback) {
this.props.loadOptions(input).then(options => {
callback(null, {options: options})
})
}
render() {
const {selectedOption} = this.state
const selectClass = this.props.meta.touched && this.props.meta.error ? "has-error form-group" : "form-group"
return (
<div className={selectClass}>
<AsyncCreatable
value={selectedOption}
onChange={this.handleChange}
loadOptions={this.loadOptions}
isLoading={false}
placeholder={this.props.label}
promptTextCreator={(label) => this.props.promtLabel(label)}
onBlur={() => this.props.input.onBlur(selectedOption.value || "")}
/>
</div>
)
}
//Function to convert incomming users in usable options (React Select)
export const convertADUsersToOptions = users => {
return users.map(user => {
return {
value: normalizeDN(user.dn),
label: user.mail
}
})
}