Create custom component input for react-day-picker - javascript

I was creating a custom materiel UI component for DayPickerInput, but the problem is when onDayChange is fired,it gives an error.
handleToDateChange = (selectedDay, modifiers, dayPickerInput) => {
const val = dayPickerInput.getInput().value;
}
Uncaught TypeError: Cannot read property 'value' of null
DayPickerInput Component
<DayPickerInput
component={props => <DatePickerCustomInput {...props} />}
value={toDate}
placeholder=""
formatDate={this.setDatePickerformatDate}
onDayChange={this.handleToDateChange}
/>
DayPickerInput Custom Component
class DatePickerCustomInput extends Component {
render() {
return (
<TextField {...this.props}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<DateRange />
</InputAdornment>
),
}}
value={this.props.value}
/>
);
}
}
to reproduce the issue : https://codesandbox.io/s/387r9plx65

Try do this!
handleToDateChange = (selectedDay, modifiers, dayPickerInput) => {
const val = dayPickerInput.state.value;
}

From the docs here. The onDayChange method has a signature of
onDayChange (day: date, modifiers: Object, e: SyntheticEvent) ⇒ void
day is a date object referring to the selected date in the picker. You don't need to pull the value out of the event to get the selected date.

Related

Material Texfield with typescript Error - The TextField is a convenience wrapper. cant be all things to all people, API would grow out of control

I am using mui textfield in a typescript wrapper components and using some props.
const TextFieldWrapper = (props: InputProps) => {
const {name, type, valid,touched, errorMessage, ...otherProps} = props;
return (
<>
<TextField name={name} type={type} variant= 'outlined' {...otherProps}/>
{!valid && touched && <ErrorMessage>{errorMessage}</ErrorMessage>}
</>
);
}
On <TextField> tag I am getting this error "The TextField is a convenience wrapper for the most common cases (80%). It cannot be all things to all people, otherwise the API would grow out of control."
When I am removing the {...otherProps} form textfield tag, the error gets removed. But I want to keep {...otherProps}. How to I resolve this problem ?
I tried this but not working:
import TextField from '#material-ui/core/TextField';
import ErrorMessage from '../ErrorMessage';
import { InputProps as TextFieldProps } from '../../../model';
import { InputProps as MuiInputProps } from 'material-ui/Input'
const TextFieldWrapper = (props: TextFieldProps) => {
const {name, type, valid,touched, errorMessage, ...otherProps} = props;
return (
<>
<TextField name={name} type={type} variant= 'outlined'
InputProps={{
inputComponent: (inputProps: MuiInputProps) => (
<MaskedInput {...otherProps} />
),
}}/>
{!valid && touched && <ErrorMessage>{errorMessage}</ErrorMessage>}
</>
);
}
export default TextFieldWrapper;
Error
Changing a textfield from self closing to having both opening and closing tags, solved a problem for me. Give it a try , it is a quick fix, not an in depth solution.

React - Material UI - TextField controlled input with custom input component with custom props

How can I pass custom props to the inputComponent?
For example, I have a MuiTextField component:
const CustomerSocialMask = React.forwardRef<HTMLElement, CustomProps>(
function CustomerSocialMask(props, ref: any) {
// deploy test
const { onChange, ...other } = props;
return (
<IMaskInput
{...other}
mask="000.000.000-00"
definitions={{
'#': /[1-9]/,
}}
inputRef={ref}
onAccept={(value: any) =>
onChange({ target: { name: props.name, value } })
}
overwrite={false}
/>
);
},
);
<MuiTextField
sx={{
'& input[type=number]': {
MozAppearance: 'textfield',
},
'& input[type=number]::-webkit-outer-spin-button': {
WebkitAppearance: 'none',
margin: 0,
},
'& input[type=number]::-webkit-inner-spin-button': {
WebkitAppearance: 'none',
margin: 0,
},
}}
variant="standard"
multiline={data.fieldType === FieldType.LONG_TEXT}
placeholder={data.settings.placeholder}
fullWidth
type={inputType}
InputProps={{
startAdornment: prefix && (
<InputAdornment position="start">
<Typography color="text.primary">{prefix}</Typography>
</InputAdornment>
),
endAdornment: suffix && (
<InputAdornment position="start">
<Typography color="text.primary">{suffix}</Typography>
</InputAdornment>
),
inputComponent: CustomerSocialMask,
}}
name={name}
onChange={
(data.settings as ShortTextSettings).valueType ===
ValueType.CURRENCY || path === PersonalDetail.PHONE
? onChange
: handleChange
}
onBlur={handleBlurWithFix}
value={valueAdjusted}
error={!!error}
helperText={error}
/>
When I try to pass custom props to the inputComponent like:
inputComponent: <CustomerSocialMask customProp={something}/>,
I get the following error:
Failed prop type: Invalid prop `inputComponent` of type `object` supplied to `ForwardRef(Input2)`, expected a single ReactElement type.
So I must only provide refs to the inputComponent, but I can't pass external data / props to the forwardRef component. I want to use a customProp inside the CustomerSocialMask component por example. How would I do that? Couldn't find anything on the docs.
Material UI TextField provides a few 'Props' style attributes to apply configuration to the child components that are combined to make the input.
Two of note are:
InputProps: This provides properties to the Material UI component that is selected based on the variant property i.e. OutlinedInput, FilledInput, etc.
inputProps: This provides properties to the underlying input which is being used, by default this is an input.
When using InputProps.inputComponent the underlying input is replaced with the provided component, this allows you to use inputProps to pass extra properties to configure the custom input.
Example:
<TextField
InputProps={{
inputComponent: CustomerSocialMask,
}}
inputProps={{
customProp: something
}}
/>
The solution seems to be very close to what you are doing, you just need to pass a function to inputComponent.
inputComponent: (props) => <CustomerSocialMask {...props} myCustomPropName={doSomething} />
Hello MUITextfield inputProps attribute can accept only the types with a normal input tag can accept (varies depending on the type), however you can use the MUI Input component to pass with custom component to use, and there the inputProps is available so you can pass the props of your custom field.
I created a quick draft in this Sandbox: https://codesandbox.io/s/react-mui-using-a-custom-component-with-input-compnent-zysvji?file=/src/App.tsx
I hope this helps.
E

MUI DatePicker's shouldDisableDate prop leading to error

<Controller
name="toDate"
control={control}
defaultValue={null}
render={({ field }) => (
<DatePicker
format="DD/MM/yyyy"
value={field.value}
onChange={(e) => { setToDate(e); field.onChange(e); }}
minDate={fromDate}
shouldDisableDate={fromDate}
/>
)}
{...register("toDate",{ required: true })}
/>
I used the shouldDisableProp to disable the date which is selected inside another datepicker whose value is stored in a state variable 'fromDate'.
But when I press the datepicker it is leading to this error.
The minDate is working perfectly fine using the fromDate state variable.
The shouldDisableDate method receives a date param and expect a boolean.
import * as React from "react";
import TextField from "#mui/material/TextField";
import AdapterDateFns from "#mui/lab/AdapterDateFns";
import LocalizationProvider from "#mui/lab/LocalizationProvider";
import DatePicker from "#mui/lab/DatePicker";
export default function BasicDatePicker() {
const [value, setValue] = React.useState<Date | null>(null);
const [fromDate, setFromDate] = React.useState<Date | null>(null);
return (
<>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DatePicker
label="From Date"
value={fromDate}
onChange={(newValue) => {
setFromDate(newValue);
}}
renderInput={(params) => <TextField {...params} />}
/>
</LocalizationProvider>
<br />
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DatePicker
label="To Date"
value={value}
onChange={(newValue) => {
setValue(newValue);
}}
minDate={fromDate}
shouldDisableDate={(dateParam) => {
//your_condition here
//return true to disabled and false to enable
const fromFormatted = fromDate.toISOString().split("T")[0];
const currentDate = dateParam.toISOString().split("T")[0];
return fromFormatted === currentDate ? true : false;
}}
renderInput={(params) => <TextField {...params} />}
/>
</LocalizationProvider>
</>
);
}
UpdatedCode
So do something like that and you will achieve your goal.
In your case, compare dateParam with your fromDate var, to return true or false and disable or not the date.
Edit: Now is adapted to your real case. Just check it out.

How to make a wrapper interchangable?

I am facing a problem with my formik fields and need to use FastFields in some situations and Fields in others. Therefor my FormikControl, a class for building formik inputs needs to switch between and as wrappers. I am not sure how to do this.
Here is part of the class:
const FormikControl = (props) => {
const {
name,
type,
label,
disabled,
fullWidth,
isDynamic, // Field (true) or FastField
} = props;
const classes = useStyles();
const inputProps = {};
switch (type) {
case 'text':
return (
<>
<ComplexField name={name} isDynamic={isDynamic} {...props}> // meant to be the wrapper that switches
{({ field }) => {
return (
<TextField
{...field}
variant="standard"
label={label}
fullWidth={fullWidth}
disabled={disabled}
InputLabelProps={{
shrink: true,
}}
InputProps={inputProps}
value={field.value || ''}
/>
);
}}
</ComplexField>
<ErrorMessage error name={name} component={FormHelperText} />
</>
);
ComplexField is meant to be the flexable wrapper and needs be able to switch between Field and FastField based on "isDynamic".
My best try was this:
const ComplexField = ({ name, children, isDynamic, ...props }) => {
return isDynamic ? (
<Field name={name} props={props}>{({ field }) => children({ ...props, field })}</Field>
) : (
<FastField name={name} props={props}>{({ field }) => children({ ...props, field })}</FastField>
);
};
Didn't work :(
<ComplexField name={name}>
You're not passing there the prop "isDynamic"
Is it intentional? Because like that it's obvious that doesnt work
<ComplexField name={name} isDynamic={isDynamic}>
If you want to use a better pattern, read that Conditionally render react components

Passing existing prop to component and appending

const LNTextField = props => {
const classes = useStylesReddit();
return (
<TextField
variant="filled"
InputProps={{ classes, disableUnderline: true }}
{...props}
/>
);
};
This is a functional component
Let's say I would like to add something to the InputProps object when using this component, while maintaining the InputProps object inside the functionalComponent
How can I do that?
for example;
<LNTextField
InputProps={{
endAdornment: (
<InputAdornment
className={styles.optionalAppendedText}
position="end"
>
Optional
</InputAdornment>
)
}}/>
Right now its overwriting the InputProps in the component
TIA
How about use different props name for InputProps from the parent? Let say, InputProps from parent is named with InputPropsParent. And, you can try to do this:
const LNTextField = props => {
const classes = useStylesReddit();
return (
<TextField
variant="filled"
InputProps={{ ...props.InputPropsParent, classes, disableUnderline: true }}
{...props}
/>
);
};
updated
As the OP comment, the above code is not working. Below code is the working code, though idk if this is the best approach or not.
const LNTextField = props => {
const classes = useStylesReddit();
return (
<TextField
variant="filled"
InputProps={{ ...props.inputpropsparent, classes, disableUnderline: true }}
{...props}
/>
);
};

Categories