How do I add all dates outside of the month while keeping the selection logic
now
i want
If i give TextField type='date', then all dates are displayed, but all my styles are lost.
My component
<MuiPickersUtilsProvider utils={MomentUtils} libInstance={momentLib}>
<DefaultKeyboardDatePicker
open={open}
value={value ?? null}
onChange={onChange}
disableIcon={disableIcon}
helperText={typeof userError === 'string' ? userError : errorNode || helperText}
error={!!userError || !!errorNode}
onClose={onClose}
renderDays={renderDay ? renderDays : void 0}
TextFieldComponent={TextField}
InputProps={{
inputRef,
inputProps: readOnly
? { readOnly: true, className: classes.readonly, onClick: onOpen, 'id-qa': idqa }
: { 'id-qa': idqa },
}}
InputAdornmentProps={{ onClick: onOpen }}
PopoverProps={{ anchorEl: inputRef.current }}
}}
{...props}
/>
</MuiPickersUtilsProvider>
I tried passing all the props and overwriting styles, nothing worked. Can i leave all styles
const WrapperTextField = () => <TextField {...props} type="date" className={clsx('MuiPickersDay-day')} />;
...
TextFieldComponent={WrapperTextField}
Wasted a lot of time. It is strange that in such a library there is no flag to show all numbers and work with them.
I would be grateful for your help!
You need to write custom renderDay function to be able to show not current month dates. Here is the example of this function in docs. To be able to select those days you need to go further and override IconButton onClick inside renderDay function. For example of code take a look at this question. As I see there is no simple way.
Related
I have the following code for a v4 mui autocomplete component, the issue with it, is that the custom popper component is casing a R14, H10 errors when deploying to heroku , indicating a major memory leak, if I remove this component which servers the purpose of styling, then things works like charm, but the issue is why would this popper component cause such a hidden leak ?, took me 17h to find the cause, I tried styling the drop down using the paper component, that is located on the autocomplete as well, but it didn't give me the styling that I want.
<Autocomplete
id='advancedselect'
ref={refAutocomplete}
options={optionsObj}
groupBy={(option: any) => option.name}
getOptionLabel={(option) => option.name}
renderOption={(option) => (
<React.Fragment>
<div style={{ width: '12vw', maxWidth: 75, marginRight: 10 }}>
<Icons img={option.equipment} />
</div>
{option.name}
</React.Fragment>
)}
disableListWrap
// Popper disabeled every thing works fine
PopperComponent={(props: any) => <Popper {...props} className={classes.propper} placement='bottom'></Popper>}
inputValue={selected.exercise}
onInputChange={handleAutoComplete}
className={classes.root}
renderInput={(params) => (
<TextField
error={err.exercise ? true : false}
onChange={handleTextField}
{...params}
InputLabelProps={{ shrink: false }}
label={selected.option}
/>
)}
/>
After long search apparently the rendered item is not getting garbage collated properly I found some solutions but I need help implementing them since I think that is the right way to stop the memory leak from happening
below is the logic for garbage collation yet not working
const [anchorEl, setAnchorEl] = React.useState(null);
const handleClick = (event: any) => {
setAnchorEl(anchorEl ? null : event.currentTarget);
};
const popperRefObject = React.useRef(null);
React.useEffect(() => {
popperRefObject && console.log(popperRefObject.current);
}, [anchorEl]);
console.log(anchorEl);
// Adding ref to to the popper
<Popper
open={Boolean(anchorEl)}
anchorEl={anchorEl}
popperRef={popperRef}
ref={popperRefObject}
// keepMounted
{...props}
className={classes.propper}
placement='top'
></Popper>
You need to reference the the popper when you open and close the menu and set the anchor element to be stable !! so it can be effectively targeted by garbage collection
// Create State
const [open, setOpen] = useState<any>({ open: false, anchorEl: null });
// Add to the autocomplete component !!!
PaperComponent={({ children }) => <Paper className={classes.backDrop}>{children}</Paper>}
PopperComponent={(props: any) => <Popper open={open.open} anchorEl={open.anchorEl} {...props} className= {classes.propper} placement='bottom'></Popper>}
// When close run funciton
onClose={() => setOpen({ /*anchorEl: null,*/ ...open, open: false })}
// When open run function
onOpen={(event: any) => {
const { currentTarget } = event;
setOpen({
anchorEl: currentTarget,
open: true,
});
}}
I have successfully integrated the creatable with react-final-form but the problem arises when i try to do an API call. I am trying to do an API call with onIputChange but whenever i get a response(in props), my drop down closes. Its closing up on receiving the new options. I tried it with normal select and it works fine. Here is my example code.
<Field
name="tags"
component={ ({
input,
...rest
}) => (<CreatableSelect {...input}
{...rest}}
/>)}
isMulti
options={sortedTagsOptions}
onInputChange={(x) => handleChangeTypeheadInput(x)}/>
The API call works fine. Only one issue occurs, the dropdown closes and goes out of focus as well as the written value goes away in the select. If anyone has any idea on how to deal with this problem please let me know. This works fine without Field component though. Maybe mutate the form values? but having problems in that regard as well.
Solved it by creating a separate component rather than doing it all in one component.
const AppCreateableSelectForm = ( {
input: {
name, onChange, value,
},
className,
incomingOptions,
isClearable,
isMulti,
onFocus,
closeMenuOnSelect,
incomingStyle,
isDisabled,
placeholder,
onInputChange,
noOptionsMessage,
}) => {
return <CreatableSelect
name={name}
isMulti={isMulti}
onFocus={onFocus}
closeMenuOnSelect={closeMenuOnSelect}
options={incomingOptions}
isClearable={isClearable}
placeholder={placeholder ? placeholder:`Select`}
className={className}
isDisabled={isDisabled}
styles={incomingStyle ? incomingStyle : style}
value={value}
onChange={onChange}
onInputChange={onInputChange}
noOptionsMessage={noOptionsMessage}
theme={theme => ({
...theme,
colors: {
...theme.colors,
primary: `#637282`,
},
})}
components={{
IndicatorSeparator: () => null,
}}
/>
Some props might not be used in this code since i copied only relative code.
I am working with React and material-ui.. I just realize i have a warning with the Autocomplete component when i try to submit the form, so i tried to do something really basic just like in the documentation:
let Form = props => {
return(
<form noValidate onSubmit={handleSubmit} >
<Autocomplete
id="combo-box-demo"
options={[{id:1,name:"test"},{id:2, name:"test2"}]}
getOptionLabel={(option) => option.name}
style={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="Combo box" variant="outlined" />}
/>
and when i try to submit the form i get the following error:
Material-UI: The value provided to Autocomplete is invalid.
None of the options match with {"id":1,"name":"test"}.
You can use the getOptionSelected prop to customize the equality test.
I also realize that if i set the options in the state of the component there is no warning (just when they are set like a constant). So i wonder if some of you have any idea of this behavior? thank you so much in advance.
Basically the reason why you get the warning is a default implementation of getOptionSelected in version 4.x.x:
getOptionSelected = (option, value) => option === value
In your case, selecting a value the following comparison happens:
// option === value:
{id:1, name:"test"} === {id:1, name:"test"} // false
Obviously, it can be true in some circumstances. In this particular case, it's false because of objects pointing to the different instances.
Solution! You have to overwrite getOptionSelected implementation:
<Autocomplete
getOptionSelected={(option, value) => option.id === value.id}
...otherProps
/>
[Update]
Note, in version 5.x.x the prop was renamed:
- getOptionSelected={(option, value) => option.id === value.id}
+ isOptionEqualToValue={(option, value) => option.id === value.id}
version 5.0
isOptionEqualToValue={(option, value) => option.value === value.value}
Also when you want to build a searcher where value you write is not necesary the same as the options you can set freeSolo to true and the warning will disapear
This Worked,
getOptionSelected={(option, value) => option.value === value.value}
https://github.com/mui-org/material-ui/issues/18514#issuecomment-606854194
Following up on elVengadors Answer:
When you want to build a searcher where the value you type in the box (the inputValue) is not necessarily one of the provided options you can set freeSolo to true.
This will stop the warning message from being displayed.
The need for this might arise if you are creating a component that allows for asynchronous querying of an API. This would cause the value of options to change based on the response from the API, but options that have already been selected before changing the inputValue to query the API may not be included in this new list of options.
In the Autocomplete Component Documentation, freeSolo is described as:
If true, the Autocomplete is free solo, meaning that the user input is not bound to provided options.
Bonus
Setting freeSolo to true will remove the pop-up button (the drop-down arrow on the right side of the Autocomplete component). To retain this button, you should also add forcePopupIcon={true}.
I had same problem after adding getOptionSelected error gone.
Error:
<Autocomplete
fullWidth={true}
label={'Location'}
margin={'noraml'}
multiple={false}
name={'location'}
value={formValues.location === '' ? {label: ''} : {label: formValues.location}}
options={location}
ref={locationRef}
onChange={useCallback((e, v) => handleInputChange(e, v))}
/>
Solution: getOptionSelected property added
<Autocomplete
fullWidth={true}
label={'Location'}
margin={'noraml'}
multiple={false}
name={'location'}
getOptionSelected={useCallback((option, value) => option.value === value.value)} // added
value={formValues.location === '' ? {label: ''} : {label: formValues.location}}
options={location}
ref={locationRef}
onChange={useCallback((e, v) => handleInputChange(e, v))}
/>
I think you should not use <form> to wrap AutoComplete component. You should set value for AutoComplete and use a function to handle on click button to submit.
Try this:
let Form = props => {
const [value, setValue] = useState({})
const handleOnSubmit = (value) => {
setValue(value)
...
}
return(
<div>
<Autocomplete
id="combo-box-demo"
value={value}
options={[{id:1,name:"test"},{id:2, name:"test2"}]}
getOptionLabel={(option) => option.name}
style={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="Combo box" variant="outlined" />}
/>
<Button onClick={() => handleOnSubmit(value)}>Submit</Button>
</div>
)
}
I have one problem in my react code.
I use Material-ui and redux-form. I have select input like and after change this select i should reset value in . I use action 'change' from react-form and set value for textfield. But label in still remains. Can i clear or reset value in ?
<Autocomplete
options={list}
getOptionLabel={option => option.name}
onInputChange={onChange}
onChange={onChangeAutoComplete}
noOptionsText='Нет доступных вариантов'
loadingText='Загрузка...'
openText='Открыть'
renderInput={params => (
<Field
{...params}
label={label}
name={fieldName}
variant="outlined"
fullWidth
component={renderTextField}
className={classes.textField}
margin="normal"
/>
)}
/>
Using hooks on the value prop breaks the functionality of the autocomplete component ( at least for me ). Using class, and setting the local state is the same.
Luckily it is a react component, so it have a "key" prop. When the key prop changes, the component is re-rendered with the default values ( which is an empty array since nothing is selected). I used hooks in the parent component and passed the values to the key prop, whenever reset is needed.
<Autocomplete
key={somethingMeaningful} // Bool, or whatever just change it to re-render the component
//...other props
/>
Hope this helps!
Material UI Autocomplete onInputChange callback provides reason argument. If input has been changed by input, reason will be input and if you selected option then reason will be reset.
onInputChange={(event, newInputValue, reason) => {
if (reason === 'reset') {
setValue('')
return
} else {
setValue(newInputValue)
}
}}
setValue is useState and you can pass value state to autocomplete value property.
use value in your <Autocomplete /> like this:
<Autocomplete
value={this.state.value} //insert your state key here
//...other props
/>
Then clear state of that key, to clear the autocomplete field value
I am going to post a very dirty way of clearing the value of Autocomplete. Try it ONLY when nothing else works;
import React, { useRef } from 'react';
...
const autoC = useRef(null);
...
<Autocomplete
...
ref={autoC}
/>
and then when you want to clear the value;
const ele = autoC.current.getElementsByClassName('MuiAutocomplete-clearIndicator')[0];
if (ele) ele.click();
This is what worked for me.
const [name, setName] = useState('');
<Autocomplete
inputValue={name}
onChange={(e,v)=>setName(v?.name||v)}
...
/>
<Button onClick={()=>setName('')}>
Clear
</Button>
You can use something like the following to clear the autocomplete field when an item is selected.
<Autocomplete
value={null}
blurOnSelect={true} />
Note that you may also need to set clearOnBlur={true} if you're using the freeSolo option.
Source https://mui.com/api/autocomplete/#props
I achieved this by updating the inputValue prop where multiple prop is false. If you are using multiple prop, then there is a propblem (bug). Selected values does not get erased.
When I encountered this, it was when options for the autocomplete changed, and wanted to clear the input value. It wouldn't clear with just the options changing. What worked for me is adding a key value onto the autocomplete which depended on the change which necessitated clearing.
To solve this, I created a hook that watches the value state of the autocomplete and set the value of the input if the checkClear returns true;
function useAutocompleteInputClear(watch, checkClear) {
const elmRef = useRef(null);
useMemo(() => {
if (!elmRef || !elmRef.current) return;
if (!checkClear || typeof checkClear !== "function") return;
const button = elmRef.current.querySelector("button")
if (checkClear(watch) && button) {
button.click();
}
}, [watch])
return elmRef;
}
Its first argument is the value that should be watched and its second argument is a function that returns a boolean. if it is true the clearing will happen.
Also, the hook returns a ref that needs to pass as ref prop to Autocomplete.
const elmRef = useAutocompleteInputClear(value, v => !v || !v.id)
<Autocomplete ref={elmRef}
value={value}
...
using onChange property we can clear the value by clicking the clear icon in the following way
<Autocomplete
fullWidth={true}
label={'Source'}
margin={'noraml'}
multiple={false}
name={'Source'}
getOptionSelected={useCallback((option, value) => option.value === value.value)}
ref={SourceRef}
value={formValues.Source === '' ? {label: ''} : {label: formValues.Source}}
options={SourceStatus}
onChange={useCallback((e, v) => {
if (typeof v === 'object' && v !== null) {
handleInputChange(e, v) // help to set the value
} else {
handleInputChange(e, {label: ''}) // help to reset the value
}
})}
/>
In my case for multiselect freeSolo onChange props 3rd argument reason solved my all issues.
AutocompleteChangeReason can be:
blur
clear
createOption
removeOption
selectOption
and 2nd arg of this props gives u already updated list of (multiselect) value/s.
onChange={(_event, newOptions, reason) => {
setOptions(
reason === 'clear' ? [] : [...newOptions.map((o) => Number(o))],
);
}}
If you need only the selected value, set the value to an empty object and render the option to your needs.
<Autocomplete
value={{}}
onChange={handleSelectionChanged}
options={options ?? []}
getOptionLabel={x => (!x ? '' : x?.name ?? '')}
renderInput={params => <TextField {...params} label="" />}
/>
If you are using objects, you can use the following code to clear the field.
Ensure you add isOptionEqualToValue:
<Autocomplete
style={{ width: 250 }}
multiple
id="checkboxes-tags-demo"
options={list}
isOptionEqualToValue={(option, newValue) => {
return option.id === newValue.id;
}}
value={selected}
onChange={(e, val) => handleSelected(e, val)}
getOptionLabel={(option) => option.name}
renderInput={(params) => (
<TextField
{...params}
label="Add to Multiple"
placeholder="Favorites" />
)} />
Just set an empty array in your state through functions, and it'll be cleared.
Try this method:
use onChange method and pass third parameter reason and compare to clear text if reason is clear then executed this function.
<Autocomplete
onChange={(event, newValue, reason) => {
if (reason === 'clear') {
console.log("Put your clear logic here: this condition executed when clear button clicked")
setValue({ title: '', year: '' }) //for reset the value
return
}
}}
/>
One easy way to do this is to pass these props to autocomplete like this:
onChange={handleSkillChange}
inputValue=''
clearOnBlur={true}
onChange is an event handler, which stores the value in the state.
inputValue='' helps to ensure that the text field inside autocomplete will always be empty
clearOnBlur={true} helps to clear the value of the autocomplete component when it loses focus.
I have the following functional component and I would like to change the font size of the textfield, but for some reason I can't figure it out. I know if I have a traditional component I can export it withStyles and set the className or InputProps, but I'm not sure how to do that with my current setup:
Class Definition:
const FormObjectText = ({id, multiline, onBlur, onChange, onFocus, placeholder, value, style, ...additionalProps}) => (
<TextField
{...additionalProps}
fullWidth
id={id}
inputProps={additionalProps.maxLength != null ? {maxLength: additionalProps.maxLength} : {}}
margin="normal"
multiline={multiline}
onBlur={onBlur}
onChange={e => onChange({ value: e.target.value })}
onFocus={onFocus}
placeholder={placeholder}
style={{
...style
}}
value={value !== null ? value : ""}
/>
);
Export from that file:
export const FORM_OBJECT_DICT = {
text: FormObjectTextStyled,
date: FormObjectDate,
// Others
};
Where it is called in another file:
{FORM_OBJECT_DICT["text"]({
value: editing ? value : getFormObjectDisplayValue(configuration, value),
onChange: this.onChange
})}
Firstly, is there any way to change the font size of the TextField using inline styles (not withStyles()), or if not, where/how would i apply withStyles() in this instance?
You can change the font size with inline styles this way:
<TextField inputProps={{ style: { fontSize: "5rem" } }} />
There is nothing about withStyles that cares whether your component is a function component or a class, so if you want to use classes, you could do something like:
const FormObjectTextStyled = withStyles(styles)(FormObjectText);
and then access the classes prop inside FormObjectText.
Here's a sandbox showing both approaches: