Remove Edit and delete button appearing in select box reactJS - javascript

I am new to reactJS. I have a select option.
I want to add delete and edit button inside the select option.
Here's the code i tried,
<Select
style={{ width: 240 }}
placeholder="Choose Web Analytics Configuration"
dropdownRender={menu => (
<div>
{menu}
<Divider style={{ margin: '4px 0' }} />
<div
style={{ padding: '4px 8px', cursor: 'pointer' }}
onMouseDown={e => e.preventDefault()}
onClick={this.openModal.bind(this)}
>
<Icon type="plus" /> Add Database
</div>
</div>
)}
>
{dbConfigList.map(item => (
<Option key={item}>{item}
<Icon onClick={this.editFun.bind(this)} type="edit" style={{ fontSize: '20px', color: 'green' }} theme="outlined" />
<Icon onClick={this.deleteFun.bind(this)} type="delete" style={{ fontSize: '20px', color: '#CC160B' }} theme="outlined" />
</Option>
))}
</Select>
I have successfully added the buttons.
Here it looks like:
But when the User selects the option, the edit and delete button appears in the select box. I only needed the name to be shown and not buttons.
Here it looks like,
Help me with some solutions to fix it and inside the dropdown menu of every each option, I want the edit and delete buttons to be appeared at the right corner. Now it was appearing after the text. i can use margin for that. but every name size differs. Ex. Some names will be 6 characters and some will be more than 6 characters. Help me with some solutions.

Check the below example, you need to prevent your <Icon> as I had done for '+ -'
should be like:
{
dbConfigList.map(item => (
<Option key={item}>
{item}
{selectedValue !== item // you need to add state
<Icon
onClick={this.editFun.bind(this)}
type="edit"
style={{ fontSize: "20px", color: "green" }}
theme="outlined"
/>
<Icon
onClick={this.deleteFun.bind(this)}
type="delete"
style={{ fontSize: "20px", color: "#CC160B" }}
theme="outlined"
/> : null}
</Option>
));
}
class App extends React.Component {
constructor() {
super();
this.state = {
optionsdata : [
{key:'101',value:'Lion'},
{key:'102',value:'Giraffe'},
{key:'103',value:'Zebra'},
{key:'104',value:'Hippo'},
{key:'105',value:'Penguin'}
],
selectedValue: null // store selected value
}
}
handleChange = (e) => {
console.log(e.target.value);
var value = this.state.optionsdata.filter(function(item) {
return item.key == e.target.value
})
this.setState({ selectedValue: value[0].value }); // set state
console.log(value[0].value);
}
render() {
const { selectedValue } = this.state;
return (
<select onChange={this.handleChange}>
{this.state.optionsdata.map(function(data, key) { return (
<option key={key} value={data.key}>{data.value} {selectedValue !== data.value ? '+ -' : null } </option> )
})}
</select>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.0.1/react-dom.min.js"></script>
<div id="app"></div>

Demo App: https://codesandbox.io/s/button-in-select-menuitem-reactjs-demo-1zyvj
I solved this problem in material-Ui design by using onOpen={() => setIconVisibile(true)} and onClose={() => setIconVisibile(false)} callbacks to set the visibility of icons.
const [isIconVisibile, setIconVisibile] = React.useState(false);
<Select
onOpen={() => setIconVisibile(true)}
onClose={() => setIconVisibile(false)}
>
<MenuItem value={1}>
{"ONE"}
{isIconVisibile ? (
<ListItemSecondaryAction variant="outlined">
<IconButton edge="end" aria-label="delete">
<DeleteIcon />
</IconButton>
</ListItemSecondaryAction>
) : null}
</MenuItem>
</Select>

Related

Add a text field in MUI Autocomplete options dropdown

I want to add an editable text field in dropdown options of MUI Autocomplete.
I was able to add MUI text field by adding it in renderOption prop of Autocomplete.
Problem
I am not able to edit the text fields since the autocomplete selection overrides it.
<Autocomplete
open={open}
multiple
value={!!value ? [value] : []}
classes={{ popupIndicatorOpen: classes.popupOpen }}
closeIcon={null}
popupIcon={<KeyboardArrowDownIcon style={{ opacity: 0.6 }}/>}
forcePopupIcon
style={{ width: 300 }}
options={options} //array
getOptionLabel={opt => isInstanceOfIRange(opt) ? Concatenate([opt.min.value, opt.max.value], ' - ') : opt.value.toString() || ''}
renderTags={(opts, getTagProps) =>
opts.map((opt, index) => (
<CustomTag key={index.toString()} opt={opt} {...getTagProps({ index })} classes={classes} />)
)}
onChange={handleChange}/
renderInput={params => (
<TextField
{...params}
label={props.label}
variant='filled'
onFocus={() => setOpen(true)}
onInput={onInputChange}
/>
)}
renderOption={(option, { selected }) => (
<CustomOption option={option} selected={selected} />
)}
PopperComponent={PopperComponent}
PaperComponent={PaperComponent}
/>
Custom Options rendering text box
const CustomOption = ({ selected, option }) => (
<div style={{ display: 'flex', flexDirection: 'row' }}>
<Checkbox
size="small"
color="primary"
checked={selected}
style={{ marginRight: 8 }}
icon={<RadioButtonUncheckedIcon />}
checkedIcon={<RadioButtonCheckedIcon />}
/>
{
isInstanceOfIRange(option) ? <RangeRender option={option} /> : <SingleRender
option={option} />
}
</div>
);
The Two text boxes are rendered using this component
const RangeRender = ({ option: { min, max } }) => {
const { labelPostfix, labelPrefix } = useContext(DropDownContext);
const inputProps = labelPrefix ? {
startAdornment: <InputAdornment position="start">{labelPrefix}</InputAdornment>,
} : labelPostfix ? { endAdornment: <InputAdornment position="end">{labelPostfix}
</InputAdornment>,} : {};
return (
<Box style={{ display: 'flex', gap: 12 }}>
<NummberField
type="number"
variant="outlined"
value={min.value}
InputProps={inputProps}
/>
<NummberField
type="number"
variant="outlined"
value={max.value}
InputProps={inputProps}
/>
</Box>);
};

How can we send JSX Element as radio button in MUI Autocomplete render options

I am using the MUI Autocomplete.
And here is the code am sending a JSX Element[] with radio buttons.
Tryout.JSX
const [selectedValue, setSelectedValue] = React.useState('a');
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSelectedValue(event.target.value);
};
<AutoCompleteSelect
optionsData={[
{
text: 'Last month',
element: (
<div>
{' '}
<Radio
checked={selectedValue === 'a'}
testid="testRadioWrapper"
value={'a'}
onChange={(event) => handleChange(event)}
/>
a
</div>
),
},
{
text: 'Last 10 month',
element: (
<div>
{' '}
<Radio
checked={selectedValue === 'b'}
testid="testRadioWrapper"
value={'b'}
onChange={(event) => handleChange(event)}
/>
b
</div>
),
},
]}
/>
Receiving optionsData props to Autocomplete.jsx file.
Autocomplete.JSX
<Autocomplete
disablePortal
id="single-select"
options={optionsData}
data-testid={testid}
getOptionLabel={(option) => option.text}
open={true}
autoHighlight={false}
disableClearable
renderOption={(props, option, { selected }) =>
<MenuItem {...props}>{option.element}</MenuItem>
}
popupIcon={
showList ? (
<i
className="icon-UpAlternative"
aria-hidden="true"
style={{
fontSize: 11,
color: Skin.colors.blackLight.value,
}}
></i>
) : (
<i
className="icon-DownAlternative"
aria-hidden="true"
style={{
fontSize: 11,
color: Skin.colors.blackLight.value,
}}
></i>
)
}
renderInput={(params) => (
<TextField
{...params}
label=""
placeholder=""
data-testid="inputSearchFilter"
/>
)}
/>
While rendering the options and clicking the radio button inside the list is giving a run time error.
enter image description here
Does anyone know why this happens?

Show length of an array based on what is left in array after its sliced

I have a react component that upon clicking showMore. it will load more comments. The issue im facing is that
View {showMore} More Comments
is not showing the items that are left in the array. Currently there are 7 comments in an array, and if you click show more, it will initially read show 3 more, but when i click again it says show 6 more. when it should be a lesser number than 6. It should be like show 2 more, etc. I'm quite confused on how to go about writing this logic.
What am i doing wrong
CommentList.tsx
import React, { Fragment, useState } from "react";
import Grid from "#material-ui/core/Grid";
import List from "#material-ui/core/List";
import Typography from "#material-ui/core/Typography";
import CommentItem from "./../commentItem/CommentItem";
import moment from "moment";
import OurLink from "../../../common/OurLink";
import OurSecondaryButton from "../../../common/OurSecondaryButton";
import OurModal from "../../../common/OurModal";
.....
function CommentList(props: any) {
const [showMore, setShowMore] = useState<Number>(3);
const [openModal, setOpenModal] = useState(false);
const [showLessFlag, setShowLessFlag] = useState<Boolean>(false);
const the_comments = props.comments.length;
const inc = showMore as any;
const showComments = (e) => {
e.preventDefault();
if (inc + 3 <= the_comments) {
setShowMore(inc + 3);
} else {
setShowMore(the_comments);
}
// setShowLessFlag(true);
};
........
const showMoreComments = () => {
return props.comments
.slice(0, showMore)
.sort((a, b) => a.id - b.id)
.map((comment, i) => (
<div key={i}>
<List style={{ paddingBottom: "20px" }}>
<img alt="gravatar" style={{ margin: "-10px 15px" }} src={comment.author.gravatar} width="30" height="30" />
<Typography style={{ display: "inline-block", fontWeight: 700, padding: "5px 0px" }} variant="h6" align="left">
{Object.entries(props.currentUser).length === 0 ? (
<Fragment>
<span style={{ cursor: "pointer", fontSize: "12px", fontWeight: isBold(comment) }} onClick={handleClickOpen}>
{comment.author.username}
</span>
{comment.userId === props.userId && <span style={{ fontSize: "12px" }}> (OP)</span>}
{openModal ? <OurModal open={openModal} handleClose={handleCloseModal} /> : null}
</Fragment>
) : (
<Fragment>
<OurLink
style={{ fontSize: "12px", fontWeight: isBold(comment) }}
to={{
pathname: `/profile/${comment.author.username}`,
}}
title={comment.author.username}
/>
{comment.userId === props.userId && <span style={{ fontSize: "12px" }}> (OP)</span>}
</Fragment>
)}
</Typography>
<div style={ourStyle}>
<CommentItem comment={comment} user={props.user} postId={props.postId} {...props} />
<Typography style={{ fontSize: "12px" }} variant="body1" align="left">
{moment(comment.createdAt).calendar()}
</Typography>
</div>
</List>
</div>
));
};
console.log(props.comments.slice(0, showMore).length);
return (
<Grid>
<Fragment>
<div style={{ margin: "30px 0px" }}>
<OurSecondaryButton onClick={(e) => showComments(e)} component="span" color="secondary">
View {showMore} More Comments
</OurSecondaryButton>
</div>
</Fragment>
{showLessFlag === true ? (
// will show most recent comments below
showMoreComments()
) : (
<Fragment>
{/* filter based on first comment */}
{props.comments
.filter((item, i) => item)
.sort((a, b) => b.id - a.id)
.slice(0, showMore)
.map((comment, i) => (
<div key={i}>
<List style={{ paddingBottom: "20px" }}>
<img alt="gravatar" style={{ margin: "-10px 15px" }} src={comment.author.gravatar} width="30" height="30" />
<Typography style={{ display: "inline-block", fontWeight: 700, padding: "5px 0px" }} variant="h6" align="left">
{Object.entries(props.currentUser).length === 0 ? (
<Fragment>
<span style={{ fontSize: "12px", cursor: "pointer", fontWeight: isBold(comment) }} onClick={handleClickOpen}>
{comment.author.username}
{comment.userId === props.userId && <span style={{ fontSize: "12px" }}> (OP)</span>}
</span>
{openModal ? <OurModal open={openModal} handleClose={handleCloseModal} /> : null}
</Fragment>
) : (
<Fragment>
<OurLink
style={{ fontSize: "12px", fontWeight: isBold(comment) }}
to={{
pathname: `/profile/${comment.author.username}`,
}}
title={comment.author.username}
/>
{comment.userId === props.userId && <span style={{ fontSize: "12px" }}> (OP)</span>}
</Fragment>
)}
</Typography>
<div style={ourStyle}>
<CommentItem comment={comment} user={props.user} postId={props.postId} {...props} />
<Typography style={{ fontSize: "12px" }} variant="body1" align="left">
{moment(comment.createdAt).calendar()}
</Typography>
</div>
</List>
</div>
))}
</Fragment>
)}
</Grid>
);
}
// prevents un-necesary re renders
export default React.memo(CommentList);
You want to show 3 more comments each time, or 1-2 items if there are less than 3 items left. So "View 3 More comments" if there are more than 3 left, or "View 1/2 More Comments" if there are only 1 or 2 left.
Or in other words cap the number of new comments shown at 3:
the minimum value of either 3 or (total number of comments - current shown comments = number of comments left).
View {Math.min(3, the_comments - inc)} More Comments

OnChange for Storing Value of Selected Drop Down Option

I have a Material UI dropdown menu. I will make a search later on the basis of the selected option from the drop down menu. How exactly could I use onChange() to store the option selected?
For now, I am trying to print the stored value (criteria) using typography at the end but instead of showing the selected value, I get a black page.
export default class userSearchPage extends Component<{}, { searchItem: string, criteria: string }>{
constructor(props: Readonly<{}>) {
super(props);
this.state = {
searchItem: '',
criteria: '',
};
this.handleDropDownChange = this.handleDropDownChange.bind(this);
}
handleDropDownChange(selected: any) {
this.setState({
criteria: selected
});
}
render() {
return (
<div>
<PermanentDrawerLeft></PermanentDrawerLeft>
<div className='main-content'>
<MuiThemeProvider>
<DropDownMenu onChange = {this.handleDropDownChange}>
<MenuItem style={{ fontSize: "20px" }} primaryText="Search By" />
<MenuItem value={1} style={{ fontSize: "20px" }} primaryText="First Name" />
<MenuItem value={2} style={{ fontSize: "20px" }} primaryText="Last Name" />
<MenuItem value={3} style={{ fontSize: "20px" }} primaryText="Phone Number" />
<MenuItem value={4} style={{ fontSize: "20px" }} primaryText="Email" />
</DropDownMenu>
</MuiThemeProvider>
<Typography>{this.state.criteria}</Typography>
<br></br><br></br>
<SearchBar
onChange={e => this.setState({ searchItem: e })}
value = {this.state.searchItem}
onRequestSearch={() => console.log('onRequestSearch')}
style={{
margin: '0 auto',
maxWidth: 800
}}
/>
<Typography>{this.state.criteria}</Typography>
</div>
</div>
);
}
}
How could I fix this?
Note: This is typescript
Added
export default class userSearchPage extends Component<{}, { searchItem: string, criteria: any}>{
constructor(props: Readonly<{}>) {
super(props);
this.state = {
searchItem: '',
criteria: null,
};
this.handleDropDownChange = this.handleDropDownChange.bind(this);
}
handleDropDownChange(event: any) {
console.log(event.target.value);
this.setState({
criteria: event.target.value
});
}
render() {
return (
<div>
<PermanentDrawerLeft></PermanentDrawerLeft>
<div className='main-content'>
<InputLabel id="demo-simple-select-label">Search By</InputLabel>
<Select
value={this.state.criteria}
onChange={this.handleDropDownChange}
displayEmpty
>
<MenuItem disabled value=" ">
<em>Search By</em>
</MenuItem>
<MenuItem value={1}>First Name</MenuItem>
<MenuItem value={2}>Last Name</MenuItem>
<MenuItem value={3}>Phone Number</MenuItem>
<MenuItem value={4}>Email</MenuItem>
</Select>
</div>
</div>
);
}
}
Assuming the DropDownMenu component is just a Material-UI Select component (https://material-ui.com/components/selects/#select), you need to update the state of your searchItem to the value of the selected MenuItem.
<DropDownMenu onChange={event => {this.setState({searchItem: event.target.value})}>
Note, currently in your example the first name and last name item are using the same value of 1.
Update - added the comment that contained the solution's code:
Here's an example using Material-UI's Select component instead of DropDownMenu: https://codesandbox.io/s/eager-hugle-tlfri
DropDownMenu menu should have the 'onChange' event that receives selected option as argument, which you can store in the components state
You could use the onChange event to do something when the user is selecting an option. If you want information, you could look at this article: https://www.w3schools.com/jsref/event_onchange.asp

change the font size of the checkbox and radio buttons labels

I am trying to change the font size of the checkbox and radio buttons labels.
I tried giving css to this component Checkbox but it's not changing the label's font size
since the labels are added dynamically.
so I researched and found this links. https://material-ui.com/api/radio/#css https://material-ui.com/customization/components/#overriding-styles-with-classes
but this is not helping me.
can you tell me how to fix it.
providing my code snippet and sandbox below.
https://codesandbox.io/s/material-demo-u95z5
const styles = theme => ({
root: {
display: "flex"
},
formControl: {
margin: theme.spacing.unit * 3
},
group: {
margin: `${theme.spacing.unit}px 0`
},
checkboxCSS: {
border: "1px solid red",
fontSize: 40
}
});
return (
<div className={classes.root}>
<FormControl component="fieldset" className={classes.formControl}>
<FormLabel component="legend">Gender</FormLabel>
<RadioGroup
aria-label="Gender"
name="gender1"
className={classes.group}
value={this.state.value}
onChange={this.handleRadioValueChange}
>
{radioValues.map(radio => {
return (
<FormControlLabel
value={radio.value}
control={<Radio />}
label={radio.label}
/>
);
})}
</RadioGroup>
{checkBoxvalues.map((check, index) => {
console.log("this.state[check.value]", this.state[check.value]);
return (
<FormControlLabel
key={check.value}
control={
<Checkbox
checked={check.checked}
onChange={this.handleCheckBoxChange(check.value, index)}
value={check.value}
className={classes.checkboxCSS}
/>
}
label={check.label}
/>
);
})}
</FormControl>
</div>
);
This link helped me: https://material-ui.com/api/form-control-label/#css
The following works in your sandbox.
In the classes object:
{
...,
checkboxLabel: {
fontSize: 40
}
}
On the FormControlLabel component add:
classes={{
label:classes.checkboxLabel
}}

Categories