React, dynamic dropdown downshift - javascript

Im fairly new to React and i'm trying to create a dropdown where users can add values to the dropdown. Something like this What i want
This is what i got now, but the add button dosent work at all
My dropdown
I had another input field where i could pass the value to the dropdown, but when i tried to implement the logic to the downshift dropdown nothing happened. No error, no value!
Here is my code:
function BasicAutocomplete({ items, onChange }) {
return (
<Downshift
onChange={onChange}
render={({
getInputProps,
getItemProps,
isOpen,
inputValue,
selectedItem,
highlightedIndex,
handleSubmit
}) => (
<div>
<Input {...getInputProps({ placeholder: 'Markedsaktivitet'}) } ref="input" />
{isOpen ? (
<div style={{ border: '1px solid #ccc' }}>
{items
.filter(
i =>
!inputValue ||
i.toLowerCase().includes(inputValue.toLowerCase()),
)
.map((item, index) => (
<div
{...getItemProps({ item }) }
key={item}
style={{
backgroundColor:
highlightedIndex === index ? 'gray' : 'white',
fontWeight: selectedItem === item ? 'bold' : 'normal',
}}
>
{ item }
</div>
))}
<Button type="button" onClick={handleSubmit}><i className="fa fa-plus" /> Add option</Button>
</div>
) : null}
</div>
)}
/>
)
}
class Dropdown extends React.Component {
constructor(props) {
super(props)
this.state = {
inputField: 'no value',
items: ['apple', 'orange', 'carrot']
}
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit() {
const newItem = this.refs.input.value
this.setState({ items: this.state.items.concat(newItem) })
}
render() {
return (
<Wrapper>
<BasicAutocomplete
items={this.state.items}
onChange={selectedItem => console.log(selectedItem)}
onClick={this.handleSubmit}
/>
</Wrapper>
);
}
}
Thanks for the replays!

use bootstrap dropdown menu its good and nice looking
check out
and maybe you find something
Check here there is diffrent model

Related

How to access index of .map() method outside of it in react

I want to access the index number outside of that map method because I want to use that index conditionally to show other component like if that index is checked then the component will show but I can't figure out how to access that outside of that map method. I have googled it but couldn't find any proper solution of that.
Here is my code!
import React, { Component, Fragment } from "react";
import Clear from "./clear";
import Display from "./display";
import NoOfItems from "./noOfItems";
class MainPage extends Component {
constructor() {
super();
this.state = {
data: [
{
name: "",
completed: false,
},
],
data: [],
checkValue: false,
};
}
handleChange = (e) => {
e.preventDefault();
this.setState({ name: e.target.value });
};
handleSubmit = (e) => {
e.preventDefault();
this.setState({
data: [...this.state.data, { name: this.state.name, completed: false }],
});
e.target.reset();
};
handleDelete = (index) => {
const newList = [...this.state.data];
newList.splice(index, 1);
this.setState({ data: newList });
};
handleAllCheck = (e) => {
e.preventDefault();
};
handleCheckChange = (index) => {
let newData = [...this.state.data];
newData[index].completed = !newData[index].completed;
this.setState({ data: newData });
};
render() {
return (
<Fragment>
<h1 className="display-1 text-center" style={{ color: "#f7c6c6" }}>
todos
</h1>
<form className="todo-form" onSubmit={this.handleSubmit}>
<label className="label" onClick={this.handleAllCheck}>
^
</label>
<input
autoFocus
type="text"
onChange={this.handleChange}
className="new-todo shadow-lg p-3 mb-5 bg-white"
placeholder="What needs to be done?"
/>
<ul className="list-group">
{this.state.data.map((data, index) => {
return (
<div key={"todo-" + index} className="div-list">
<input
className="check"
onChange={() => this.handleCheckChange(index)}
type="checkbox"
style={{
cursor: "pointer",
}}
defaultChecked={this.state.data.completed}
/>
<li
className="list-group-item disabled w-50 p-3 mx-auto"
style={{
textDecoration:
this.state.data[index].completed && "line-through",
}}
>
{data.name}
</li>
<button
onClick={() => this.handleDelete(index)}
type="button"
className="close"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
</div>
);
})}
</ul>
{this.state.data.length > 0 && <Display />}
{this.state.data.length > 0 && (
<NoOfItems noOfTodos={this.state.data.length} />
)}
{this.state.data.completed && <Clear />}
</form>
</Fragment>
);
}
}
export default MainPage;
Just ignore the rest and see the map method and its index. At the end of the code I have used this.state.data.completed at this point I want to use the index like this this.state.data[index].completed but its saying invalid declaration of Index. Please help me I am stuck!
Thank you in advance!

React Conditional Rendering of Component Inside Function Not Working

I am using Codesandbox to work on learning React. I am trying to conditionally render a functional React component inside of a function (inside of a class based component), that fires when a button is clicked.
Here is the link to the Codesandbox: https://codesandbox.io/embed/laughing-butterfly-mtjrq?fontsize=14&hidenavigation=1&theme=dark
The issue I have is that, without importing and rendering the Error and Meals in App.js, I never can get either component to render from the Booking component. In the function here:
if (!this.state.name) {
return (
<div>
<Error />
</div>
);
}
else {
return <Meals name={this.state.name} date={this.state.date} />;
}
}
I should be rendering Error, which should then show on the screen on click if no name is inputted but nothing happens and I am stumped.
Is there anything obvious that would be preventing me from seeing the Error component from loading on the click?
Thank you in advance!
Everything that is displayed on the screen comes from render method. You cann't return JSX from any function like that. You can do something like this:
class Bookings extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
date: "",
display: false
};
}
guestInfoHandler = event => {
console.log(this.state, "what is the state");
this.setState({ name: event.target.value });
};
dateInfoHandler = event => {
this.setState({ date: event.target.value });
};
showMeals = () => {
this.setState({ display: true });
};
render() {
return (
<>
<div style={{ display: "inline-block" }}>
<form
className="theForm"
style={{
height: "50px",
width: "100px",
borderColor: "black",
borderWidth: "1px"
}}
>
<label className="theLabel">
Name:
<input
className="theInput"
type="text"
placeholder="guest name here"
onChange={this.guestInfoHandler}
value={this.state.value}
/>
</label>
</form>
<form>
<label>
Date:
<input
type="text"
placeholder="date here"
onChange={this.dateInfoHandler}
value={this.state.value}
/>
</label>
</form>
<button onClick={() => this.showMeals()}>Click</button>
</div>
{ display && name ? (
<Meals name={name} date={name} />
) : (
<Error />
)}
</>
);
}
}
export default Bookings;
Hope this works for you.
render() {
const name = this.state.name;
return (
<div>
{name ? (
<Meals name={name} date={name} />
) : (
<Error />
)}
</div>
);
}
nb:use render method in class component only.
there is various types conditional rendering mentioned in
https://reactjs.org/docs/conditional-rendering.html#

Custom SingleValue and Option react-select - Option displays, but SingleValue doesn't

I'm trying to create a custom Select using react-select. I want to create a custom Option and SingleValue. The custom Option renders, but SingleValue doesn't. The single value (selected value) displays as per the default styling.
Here's my code,
const Option = (props) => {
const { data, innerProps, innerRef, cx, getStyles, className } = props;
const [hover, setHover] = useState(false);
return (
<div ref={innerRef} {...innerProps}
style={getStyles('option', props)}
className={cx(
{
option: true,
},
className
)}
>
<div style={{ marginLeft: 10}} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}>
<p> {data.label} </p>
{ hover ? <Alert bsStyle="success" style={{ opacity: 0.8 }}>
<p> {data.description} </p>
</Alert> : null}
</div>
</div>
)
};
I have tried SingleValue like this,
const SingleValue = ({
cx,
getStyles,
selectProps,
data,
isDisabled,
className,
...props
}) => {
console.log(props);
return (
<div
className={cx(
emotionCss(getStyles("singleValue", props)),
{
"single-value": true,
"single-value--is-disabled": isDisabled
},
className
)}
>
<div>{data.label}</div>
<div style={{ fontSize: "10px" }}>{data.description}</div>
</div>
);
};
And this,
const SingleValue = props => (
<components.SingleValue {...props}>
{props.data.description}
</components.SingleValue>
);
I render it like this,
<Select
id="color"
options={this.props.options}
isMulti={true}
onChange={this.handleChange}
onBlur={this.handleBlur}
value={this.props.value}
components={{ Option, SingleValue }}
/>
Both ways of SingleValue don't work. I have tried to just include SingleValue in components, but that also does't work. Could anyone please help? Thanks!
I had the same problem and I solved it using components.ValueContainer instead of components.SingleValue. In my case, I used react-select to have an icon select component.
This is my constructor:
constructor(props) {
super(props);
this.state = {
icons: [{label: "temperature-low", value: "temperature-low", icon: "temperature-low"}, {label: "utensils", value: "utensils", icon: "utensils"}, {label: "venus", value: "venus", icon: "venus"}, {label: "volume-up", value: "volume-up", icon: "volume-up"}, {label: "wifi", value: "wifi", icon: "wifi"}],
inputValueIcon: "",
};
this.handleChangeIcon = this.handleChangeIcon.bind(this);
}
This is my handleChange function:
handleChangeIcon(selectedItem) {
this.setState({
inputValueIcon: selectedItem
})
}
And finally, my render function:
render() {
const { Option, ValueOption, ValueContainer } = components;
const IconOption = (props) => (
<Option {...props}>
<MDBIcon icon={props.data.label} />
</Option>
);
const ValueOptionLabel = (props) => (
<ValueContainer {...props}>
<MDBIcon icon={props.data.label} />
</ValueContainer>
);
return(
<Fragment>
<Select
placeholder="Select an icon"
value={this.state.inputValueIcon}
onChange={ this.handleChangeIcon }
components={{ Option: IconOption, SingleValue: ValueOptionLabel }}
options={ this.state.icons }
/>
</Fragment>
);
}
It's not the best solution, but it works :)

how to change value of 'select' manually after rendering the component in react

I have set the value of Select to local state variable. child component updates that state change. but the drop down won't be able to change the selected value.
Please can someone check the below code and correct me.
Thank you
Parent Component
class EditVehicle extends Component {
constructor(props) {
super(props);
this.state = {
values: {
vehicleOwner: '',
},
}
}
setVehicleOwner = (owner) => {
console.log(owner);
this.setState({ vehicleOwner: owner._id });
};
render() {
const { values } = this.state;
return (
......
<FormControl className={classes.formControl} >
<Select
value={this.state.values.vehicleOwner}
onChange={this.handleChange}
inputProps={{
name: 'vehicleOwner',
id: 'vehicleOwner',
}}>
{this.props.vehicleOwnersList && this.props.vehicleOwnersList.map((owner, index) => (
<MenuItem value={owner._id} key={index}>{owner.firstName} {owner.lastName}</MenuItem>
))}
</Select>
<Tooltip title="New Vehicle Owner">
<IconButton className={classes.button} aria-label="New Vehicle Owner" color="primary" onClick={this.handleOpenOwnerCreateModal}>
<AddIcon />
</IconButton>
</Tooltip>
</FormControl>
......
<Modal
aria-labelledby="simple-modal-title"
aria-describedby="simple-modal-description"
open={this.state.openOwnerCreateModal}
className={classes.modal}
onClose={this.handleCloseOwnerCreateModal}>
<NewVehicleOwnerModal
set={this.setVehicleOwner}
selected={null}
action={this.handleCloseOwnerCreateModal} />
</Modal>
);
}
}

How to properly render jsx-like html inside of javascript

I have a react component, which renders some block with another component based on the state. How could I render both HTML-like JSX and component inside of JS?
class Feedback extends Component {
constructor(props) {
super(props);
this.state = {
storeInputShow: true
};
}
render() {
return (
<div>
{ this.state.storeInputShow ?
<div className="form_field" style={{ marginBottom: '4px' }}>
<Text textTag="div">
Select shop
</Text>
</div>
<Autocomplete
items={this.state.storeList}
shouldItemRender={(item, value) => item.label && item.label.toLowerCase().indexOf(value.toLowerCase()) > -1}
getItemValue={item => item.label}
renderItem={(item, highlighted) =>
<div
key={item.id}
style={{ backgroundColor: highlighted ? '#eee' : '#ffffff', ...selectItemStyle }}
>
{item.label}
</div>
}
value={store}
onChange={e => this.setState({ store: e.target.value, storeId: e.target.id })}
onSelect={(store,storeCard) => this.setState({ store, storeId: storeCard.id })}
inputPlaceholder="Shop"
wrapperStyle={selectWrapperStyle}
menuStyle={selectMenuStyle}
/>
: null
}
</div>
);
}
Right now the error is the following:
SyntaxError: Adjacent JSX elements must be wrapped in an enclosing tag
at the <Autocomplete tag.
The error is self-explanatory, you should wrap both components inside one to make your conditional work.
<div>
<div className="form_field" style... />
<Autocomplete items={this.state.storeList} should... />
</div>
You could use a React.Fragment instead of <div />
BONUS: You could use the following syntax to remove the end null case
<div>
{ this.state.storeInputshow && <YourComponents /> }
</div>
That way you will only render if storeInputShow is available in the state without needing to return null if not.
You can't put if into a return, but you can put a variable.
class Feedback extends Component {
constructor(props) {
super(props);
this.state = {
storeInputShow: true
};
}
render() {
let form;
if (this.state.storeInputShow)
form = <div className="form_field" style={{ marginBottom: '4px' }}>
<Text textTag="div">
Select shop
</Text>
</div>
<Autocomplete
items={this.state.storeList}
shouldItemRender={(item, value) => item.label && item.label.toLowerCase().indexOf(value.toLowerCase()) > -1}
getItemValue={item => item.label}
renderItem={(item, highlighted) =>
<div
key={item.id}
style={{ backgroundColor: highlighted ? '#eee' : '#ffffff', ...selectItemStyle }}
>
{item.label}
</div>
}
value={store}
onChange={e => this.setState({ store: e.target.value, storeId: e.target.id })}
onSelect={(store,storeCard) => this.setState({ store, storeId: storeCard.id })}
inputPlaceholder="Shop"
wrapperStyle={selectWrapperStyle}
menuStyle={selectMenuStyle}
/>;
return (
<div>{ form }</div>
);
Problem in your code is, with in the if-condition, for true case you are returning two elements(,) but in JSX it expects every return to be one element(which can have any number of child's). So just wrap your elements in if-condition with wrapper.
class Feedback extends Component {
constructor(props) {
super(props);
this.state = {
storeInputShow: true
};
}
render() {
return (
<div>
{ this.state.storeInputShow ?
<div>
<div className="form_field" style={{ marginBottom: '4px' }}>
<Text textTag="div">
Select shop
</Text>
</div>
<Autocomplete
items={this.state.storeList}
shouldItemRender={(item, value) => item.label && item.label.toLowerCase().indexOf(value.toLowerCase()) > -1}
getItemValue={item => item.label}
renderItem={(item, highlighted) =>
<div
key={item.id}
style={{ backgroundColor: highlighted ? '#eee' : '#ffffff', ...selectItemStyle }}
>
{item.label}
</div>
}
value={store}
onChange={e => this.setState({ store: e.target.value, storeId: e.target.id })}
onSelect={(store,storeCard) => this.setState({ store, storeId: storeCard.id })}
inputPlaceholder="Shop"
wrapperStyle={selectWrapperStyle}
menuStyle={selectMenuStyle}
/>
</div>
: null
}
</div>
);
}

Categories

Resources