I have the following:
--- before render ---
const fontArray = [
["Standard", "Standard"], ["Abril FatFace", "'Abril Fatface', cursive"],
["Alfa Slab One", "'Alfa Slab One', cursive"],
["Chonburi", "'Chonburi', cursive"], ["Comfortaa", "'Comfortaa', cursive"],
["Lobster", "'Lobster', cursive"], ["Pacfico", "'Pacifico', cursive"]
]
--- in render ---
<FormControl style={{margin: '10px'}}>
<InputLabel htmlFor="select-font">Font</InputLabel>
<Select
value={this.state.font[0]}
onChange={(evt)=>this.handleFontChange(evt)}
inputProps={{
name: 'font',
id: 'select-font',
}}
>
{fontArray.map((font, index)=>{
return(
<MenuItem key={font} value={font}>
<div style={{fontFamily: `${font[1]}`}}>
{font[0]}
</div>
</MenuItem>
)
})}
</Select>
</FormControl>
And as you can guess the current font is held in state.
--- Here is how I handle select change ---
handleFontChange = (event) => {
this.setState({ font: event.target.value })
};
So what I want is to be able to have a font select, where the font is shown. It almost works. For example, when I click the select I get:
However, the select itself is empty (even when I've confirmed that state is populated:
What am I doing wrong? Maybe material-ui can't handle stylized default text?
EDIT: The two answers below seem close, but not quite right for what I'm trying to do.
If you replace
<MenuItem key={font} value={font}>
with
<MenuItem key={font} value={font[0]}>
It does replace the font with the correct selected value. Great!
...but it also then replaces this.state.font with this.state.font[0]. I'm currently attempting to get this to work by changing the handle function like this:
handleFontChange = (event, fontArray, stateData) => {
let newFont = fontArray.filter(i=>{
if(i[0]==event.target.value){
return i
}
})
this.setState({ font: newFont })
};
Which seems to set this.state.font correctly, but it again doesn't
seem to want to make the select box show the selected font.
Hmmm....
SOLVED
Here is a modification of a solution below:
Using
renderValue = (value) => {
return(
<div style={{fontFamily: `${value[1]}`}}>
{value[0]}
</div>
)
}
and
<...>
<Select
value={this.state.font}
renderValue={() => this.renderValue(this.state.font)}
<...>
Gives...
You can use renderValue to solve this.
renderValue = (value) => {
return value && value[0];
}
in render method
<FormControl style={{margin: 10}}>
<InputLabel htmlFor="select-font">Font</InputLabel>
<Select
value={this.state.font}
renderValue={() => this.renderValue(this.state.font)}
onChange={evt => this.handleFontChange(evt)}
inputProps={{
name: "font",
id: "select-font"
}}
>
{fontArray.map((font, index) => {
return (
<MenuItem key={index} value={font}>
<div style={{fontFamily: `${font[1]}`}}>
{font[0]}
</div>
</MenuItem>
);
})}
</Select>
</FormControl>
<...>
<Select
value={this.state.font?this.state.font :defaultvlue}
renderValue={() => this.renderValue(this.state.font)}
<...>
you can use ternary operator ,if you have data show data else default value
Related
facing challenges making validation classes to reflect automatically on custom datepicker Flatpickr using React-Hook-Forms,
const { register, handleSubmit, errors, control } = useForm({
mode: 'onChange'
})
<FormGroup>
<Controller
name="dateControl"
control={control}
defaultValue={null}
rules={{ required: true }}
render={({ value, onChange }) => (
<Flatpickr
value={value}
onChange={onChange}
id="hf-picker"
options={{
altInput: true,
altFormat: 'F j, Y',
dateFormat: 'Y-m-d',
altInputClass: classnames(
'form-control flatpickr-input',
{
'is-invalid': errors.dateControl && true
}
)
}}
/>
)}
/>
</FormGroup>
After troubleshooting, I realize everything works except that component fails to re-render whenever the validation errors are updated by react-hooks-form, is there anyway I can force a manual re-render instead, thanks
I think this has nothing to do with RHF, but somehow the options prop of the <Flatpickr /> component isn't updated when the config changes.
I'm assuming your using the react-flatpickr package - what you could do is simply pass the key prop to this component and setting it to the errors object of that control. This will force a re-render every time the errors of that form control change.
const isNotEmpty = (array) => array?.length > 0 || "Required";
<Controller
name="dateControl"
control={control}
defaultValue={null}
rules={{ validate: isNotEmpty }}
render={({ value, onChange }) => (
<>
<Flatpickr
key={errors.dateControl}
value={value}
onChange={onChange}
id="hf-picker"
options={{
altInput: true,
altFormat: "F j, Y",
dateFormat: "Y-m-d",
altInputClass: classnames("form-control flatpickr-input", {
"is-invalid": !!errors.dateControl
})
}}
/>
{errors.dateControl && <p>{errors.dateControl.message}</p>}
</>
)}
/>
I am trying to change the style (colors) of elements in list items as they are created from a map function, which provides the rgb-color.
Using classes works, but to get it right dynamically, sofor the data/color provided by the object array is a problem.
The attempts beneath do show e.g. fill="rgb(48, 183, 0)", but the classes which define it's style still override the dynamically added style
<Select
multiple
value={filterList[index]}
renderValue={(selected) => selected.join(", ")}
onChange={(event) => {
filterList[index] = event.target.value;
onChange(filterList[index], index, column);
}} >
{ processStatusColorsArr.map(({ id, name, color} ) =>(
MenuItem key={id} value={name} style={{ fill: `${color}%`, color: `${color}%` }} >
<Checkbox
fill={color} style={{ fill: `${color}%`, color: `${color}%` }} />
<ListItemText primary={name}
color= {color} />
<IconButton color={color}
fill={color}
style={{ fill: `${color}%`, color: `${color}%` }} />
</MenuItem>
))}
</Select>
I have also tried this,
{render_filter_process_status_colors(color)} in place of '<IconButton ..../>'
where I have (above this)
const render_filter_process_status_colors = (value, tableMeta, updateValue) => {
if(value === undefined) return;
return (
<div>
<FontAwesomeIcon icon={"square"} style={value} size={"lg"} fixedWidth/>
</div>
);
}
but no luck.
Thx
By using the function
{render_filter_process_status_colors(color)}
which is defined as
const render_filter_process_status_colors = (value, tableMeta, updateValue) => {
if(value === undefined) return;
const iconColor = {color: value}
return (
<div>
<FontAwesomeIcon icon={"square"} style={iconColor} size={"lg"} fixedWidth/>
</div>
); }
I get the icon with the color from my array of rgb colors.
I've made a custom User Confirmation Dialog from Material UI Dialog component like here
I faced a problem to overwrite the Dialog's font. I can overwrite color or background color, but fonts in Dialog's header or buttons are inherited from Material-UI. I successfully overwrote Material-UI fonts in other components, but not in this part with callback:
const UserConfirmation = (
message: string,
callback: (shouldNavigate: boolean) => void
) => {
const container = document.createElement('div')
container.setAttribute('custom-confirmation-navigation', '')
document.body.appendChild(container)
const closeModal = (shouldNavigate: boolean) => {
ReactDOM.unmountComponentAtNode(container)
callback(shouldNavigate)
}
ReactDOM.render(
<>
<Dialog
fullWidth={true}
maxWidth="sm"
open={true}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitleWrapper
style={{fontFamily: `BuenosAires !important`, color: `orange`}}
>
Discard draft?
</DialogTitleWrapper>
<DialogContent>
<p> {message} </p>
</DialogContent>
<DialogActionsWrapper>
<Button
onClick={() => closeModal(true)}
fullWidth={true}
variant="outlined"
label="Discard"
/>
<div style={{ width: '80%' }} />
<Button
onClick={() => closeModal(false)}
fullWidth={true}
variant="contained"
label="Cancel"
/>
</DialogActionsWrapper>
</Dialog>
</>,
container
)
}
export default UserConfirmation
Thank Alex
That works brilliant for me:
<DialogTitle disableTypography="true">
Also, buttons' labels were fixed by that:
label={<h5 style={{ textTransform: 'none' }}>Cancel</h5>}
You can use classes object to Override or extend the styles applied to the component.
here
create custom styles like below
const useStyles = makeStyles({
customDialogTitle: {
fontFamily:'Impact'//sans-serif
}
});
and assign to classes
<DialogTitle disableTypography="true"
classes={{
root: classes.customDialogTitle
}}
>
.....
</DialogTitle>
sample sandbox
I am using the Select component of material ui. I want to customise the dropdown menu with a top arrow. I have overriden menuStyle using pseudo element before. However, the arrow appears on the screen even before clicking on the dropdown. This is because the class is used in select element as well. I want to target dropdown menu by checking for the siblings.
<Select
value={this.state.date}
onChange={this.handleChange}
displayEmpty
name='date'
autoWidth={false}
className={classes.selectWithArrow}
classes={{
icon: classes.icon,
selectMenu: classes.menuStyle,
select: classes.select,
}}
renderValue={value => this.state.date}
root={classes.root}
input={
<Input
name='date'
id="label-placeholder"
classes={{
root: classes.root,
}}
/>
}
MenuProps={{ classes: { paper: classes.menuStyle } }}
>
<MenuItem value={1}>One</MenuItem>
<MenuItem value={2}>Two</MenuItem>
<MenuItem value={3}>Three</MenuItem>
</Select>
I want to target siblings something like this -
const styles = theme => ({
'.menuStyle.selectMenu': {
'&::before': {
},
}
});
Is there any way? Any leads will be highly appreciated.
I want to position selected items from Select isMulti elsewhere.
What I did before was hide the selected values, and save the selected values on some state and display in other place.
But this way I don't have the clear indicator for this element.
handleChange = (event) => {
this.setState({secondarySelectedOptions: event});
};
render() {
const { secondarySelectedOption } = this.state;
return (
<>
<Select
isMulti
name="secondary"
options={this.state.options}
styles={{
multiValue: base => ({
...base,
display: "none"
}),
}}
onChange={this.handleChange}
value={secondarySelectedOption}
/>
</>
)
<div className='half-width'>
{this.state.secondarySelectedOptions.map((item) => (
<div>{item.value}</div>
))}
</div>