Passing existing prop to component and appending - javascript

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}
/>
);
};

Related

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

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

Material ui Autocomplete press enter to create new chips

I wish I could do such a thing using Autocomplete of material ui: wertarbyte
That is, inserting text (string) without having a list of elements from which you must select.
Therefore the noOptions message should not appear, every time the enter key is pressed on the keyboard the text is inserted.
Link: codesandbox
Code:
import React from "react";
import Chip from "#material-ui/core/Chip";
import Autocomplete from "#material-ui/lab/Autocomplete";
import { makeStyles } from "#material-ui/core/styles";
import TextField from "#material-ui/core/TextField";
const useStyles = makeStyles(theme => ({
root: {
width: 500,
"& > * + *": {
marginTop: theme.spacing(3)
}
}
}));
export default function Tags() {
const classes = useStyles();
return (
<div className={classes.root}>
<Autocomplete
multiple
id="tags-outlined"
options={[]}
defaultValue={["foo", "bar"]}
//getOptionLabel={(option) => option}
//defaultValue={[top100Films[13]]}
//filterSelectedOptions
renderInput={params => (
<TextField
{...params}
variant="outlined"
label="filterSelectedOptions"
placeholder="Favorites"
/>
)}
/>
</div>
);
}
In case you have simple elements (not objects, just strings), and you don't really need to handle state (your autocomplete is not controlled) you can use the freeSolo prop of the Autocomplete.
<Autocomplete
multiple
freeSolo
id="tags-outlined"
options={["foo", "bar"]}
defaultValue={["foo", "bar"]}
renderInput={params => (
<TextField
{...params}
variant="outlined"
label="filterSelectedOptions"
placeholder="Favorites"
/>
)}
/>
In case your elements are more complex and you do need to control the element:
Make sure the Autocomplete tag is a controlled one (you manage to value).
Listen to key down event on the TextField.
If the code is Enter (e.code === 'Enter') - take the value of the input and push it to the list of the current values that you have.
Make sure you also handle the onChange to handle the removal of elements:
Here is the code:
const [autoCompleteValue, setAutoCompleteValue] = useState(["foo", "bar"]);
return (
<Autocomplete
multiple
id="tags-outlined"
options={[]}
value={autoCompleteValue}
onChange={(e, newval, reason) => {
setAutoCompleteValue(newval);
}}
renderInput={params => (
<TextField
{...params}
variant="outlined"
label="filterSelectedOptions"
placeholder="Favorites"
onKeyDown={e => {
if (e.code === 'enter' && e.target.value) {
setAutoCompleteValue(autoCompleteValue.concat(e.target.value));
}
}}
/>
)}
/>
);
Check the live working example of both options: https://codesandbox.io/s/mui-autocomplete-create-options-on-enter-gw1jc
For anyone who wants to input the current best match on enter key press (as opposed to any custom text) you can use the autoHighlight prop.
<Autocomplete
multiple
autoHighlight
id="tags-outlined"
options={["foo", "bar"]}
defaultValue={["foo", "bar"]}
renderInput={params => (
<TextField
{...params}
variant="outlined"
label="filterSelectedOptions"
placeholder="Favorites"
/>
)}
/>
To do this, don't use the Autocomplete element from MUI. Just use a a standard TextField with the use of InputProps. All you need to do is add a onKeyDown listener to the TextField that listens for 'Enter' and when the function is triggered, have it add to an array of Chips in the InputProps. It might look something like this:
const [inputValue, setInputValue] = useState('');
const [chips, setChips] = useState([])
const inputChange = ({target: {value}}) => {setInputValue(value)};
const handleKeyDown = ({key}) => {
if(key === 'Enter') {
setChips([...chips, inputValue])
}
};
<TextField
fullWidth
variant="outlined"
label="Fish and Chips"
value={inputValue}
onChange={inputChange}
multiline
InputProps={{
startAdornment: chips.map((item) => (
<Chip
key={item}
label={item}
/>
)),
}}
/>
This is untested as written here, but it should work. I've done something similar in one of my apps.

Material-ui Autucomplete: specifying custom CloseIconButton

folks
So my issue is simple. I want to provide custom closeIconButton. And only closeIcon prop is available.
CloseIcon prop doesn't suffice because I need this custom button to have onClick property.
And if I place onClick on CloseIcon material-ui will warn: Failed prop type: Material-UI: you are providing an onClick event listener to a child of a button element.
Firefox will never trigger the event.
<Autocomplete
open={open}
classes={classes}
options={practicesList}
getOptionLabel={get('name')}
value={curPractice}
blurOnSelect
closeIcon={<CloseIcon onClick={() => onChange(null)} />}
onChange={async (e, option) => {
if (!option) return
onChange(option.id)
}}
renderInput={params => <TextField {...params} autoFocus={autoFocus} fullWidth label={label} margin="none" />}
renderOption={(practice, { inputValue }) => {
const matches = match(practice.name, inputValue)
const letters = parse(practice.name, matches)
return (
<div>
{letters.map((letter, i) => (
<span key={i} style={{ fontWeight: letter.highlight ? 700 : 400 }}>
{letter.text}
</span>
))}
</div>
)
}}
/>
From api docs closeIcon should be just some node. For example:
<CloseIcon fontSize="small" />
Than, you can use onClose prop directly on Autocomplete component to specify some callback. Hope this helps.

Create custom component input for react-day-picker

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.

Categories