Material UI select and autocomplete box not lined up - reactjs

Screenshot of misaligned drop-down boxes
Hi! I'm a beginner ReactJS engineer. I added 2 drop-down boxes from material UI, the left box is the Autocomplete from materialui/labs and the right box is the Select from materialui/core. They're both placed in the same component with the same styling applied to it, but the Autocomplete is slightly off. Is there a simple fix to this misalignment?
<AutocompleteComponent
formStyle={{ width: 200 }}
label={'Build'}
options={builds}
value={selectedBuild}
handleChange={handleFilterSelectChange('selectedBuild')} />
<SelectComponent
formStyle={{ width: 120 }}
label={'Sheet Layout'}
options={sheetLayouts}
value={selectedSheetLayout}
handleChange={handleFilterSelectChange('selectedSheetLayout')} />
For select component:
const SelectComponent = props => {
return (
<FormControl
className={className}
required={required}
error={error}
margin={margin}
style={formStyle}
>
<InputLabel>{label}</InputLabel>
<Select
inputRef={inputRef}
value={value}
style={style}
onChange={handleChange}
disabled={disabled}
onClick={onClick}
onFocus={onFocus}
onBlur={onBlur}
>
{excludeNone ? null : (
<MenuItem value="">
<em>{noneLabel ? noneLabel : "None"}</em>
</MenuItem>
)}
{optionsExist(options)}
</Select>
{helperText ? <FormHelperText>{helperText}</FormHelperText> : null}
</FormControl>
);
};
For the autocomplete component:
class AutocompleteComponent extends React.Component {
render() {
return (
<FormControl
className={className}
required={required}
error={error}
margin={margin}
style={formStyle}
>
<Autocomplete
style={style}
disabled={disabled}
onClick={onClick}
onFocus={onFocus}
onBlur={onBlur}
options={options}
getOptionLabel= {option => option.label && option.label.toString()}
id="auto-complete"
autoComplete
includeInputInList
renderInput={params => (
<TextField
{...params}
label="Builds"
margin="normal"
fullWidth
position="center"
/>
)}
renderOption={(option, { inputValue }) => {
const matches = match(option.label, inputValue);
const parts = parse(option.label, matches);
return (
<div>
{parts.map((part, index) => (
<span
key={index}
style={{ fontWeight: part.highlight ? 700 : 400 }}
>
{part.text}
</span>
))}
</div>
);
}}
/>
{helperText ? <FormHelperText>{helperText}</FormHelperText> : null}
</FormControl>
);
}
}
Thanks!

Related

stopPropogation not working consistently in React

I am working with 2 dropdown menus using stopPropogation to prevent the menu shifting up and down when items are checked and unchecked.
One menu works great but the other is still jumping up and down when checking and unchecking items, although I am confident that I'm using stopPropogation in the same way for both instances. I am wondering what I am doing wrong in the faulty dropdown menu that's causing this issue.
Working dropdown menu:
return (
<div onClick={(e) => {
e.stopPropagation();
}}>
<FormControl
variant="outlined"
size="small"
className={classes.formControl}
>
<InputLabel id="demo-mutiple-checkbox-label" align="left" margin="dense">
Select Models
</InputLabel>
<Select
multiple
labelId="demo-mutiple-checkbox-label"
label="SelectModels"
value={modelIds}
onChange={handleChange}
renderValue={(selected) =>
selected
.map(
(id) =>
deviceModelData.find((model) => model.alg_id === id).alg_name
)
.join(', ')
}
MenuProps={MenuProps}
className={classes.rootSelect}
>
{deviceModelData.map((model, index) => (
<MenuItem key={model.alg_id} value={model.alg_id}>
<Checkbox checked={modelIds.includes(model.alg_id)} />
<ListItemText primary={model.alg_name} />
</MenuItem>
))}
</Select>
</FormControl>
</div>
);
}
Problematic dropdown menu:
return (
<div
onClick={(e) => {
e.stopPropagation();
}}
>
<FormControl
variant="outlined"
size="small"
className={classes.formControl}
>
<InputLabel id="demo-mutiple-checkbox-label">Select Classes</InputLabel>
<Select
labelId="demo-mutiple-checkbox-label"
label={label}
id="demo-mutiple-checkbox"
multiple
value={classIds}
onChange={handleClassIdsChange}
renderValue={(selected) =>
selected
.map((id) => marketplaceModelClasses[id].original_label)
.join(', ')
}
MenuProps={MenuProps}
>
{allClassIds.map((classId) => {
return (
<MenuItem key={classId} value={classId}>
<Checkbox
value={classId}
checked={classIds.indexOf(classId) > -1}
/>
<ListItemText
primary={marketplaceModelClasses[classId].original_label}
/>
</MenuItem>
);
})}
</Select>
</FormControl>
</div>
);
}

How to display data from html response body on textfield or textArea in material UI reactjs?

I have a form. On clicking the 'Evaluate' button, I send a post request. The response of this request is JSON, which I need to display in textField named Output.
How to display data in 'Output' textField?
I just need to display data(which is json in this case) to the text field.
My text field looks like this:
const MyTextField = ({select, values, nullable, min, max, helpertext, ...props}) => {
const [field, meta] = useField(props);
return (
<TextField
select={!!select}
variant="outlined"
margin="dense"
//{...field}
//defaultValue={meta.initialValue}
value={field.value}
error={meta.touched && meta.error}
helperText={(meta.touched && meta.error) ? meta.error : helpertext}
onChange={field.onChange}
onBlur={field.onBlur}
InputProps={{inputProps: {min: min, max: max}}}
{...props}
>
{
values && nullable && values instanceof Array && <MenuItem ><em>None</em></MenuItem>
}
{
values && values instanceof Array && values.map((value, index) => {
return <MenuItem key={value} value={value}>{value}</MenuItem>
})
}
</TextField>
);
};
and form looks like this
return (
<Container fluid className="main-content-container px-4">
<Row noGutters className="page-header py-4">
<PageTitle sm="12" title="Transformer Tester Tool" subtitle="" className="text-center"/>
</Row>
<Paper id="connPageRoot" className={classes.testerRoot}>
<Formik onSubmit={submitEvaluate} initialValues={request}>
<Form>
<div>
<MyTextField
variant="outlined"
margin="dense"
id="json2JsonTransformationConfigDto.template"
name="json2JsonTransformationConfigDto.template"
label="JSLT template"
multiline={true}
rowsMax={4}
fullWidth={true}/>
</div>
<div>
<MyTextField
variant="outlined"
margin="dense"
id="inputs.0"
name="inputs.0"
label="Json payload to be tested"
multiline={true}
rowsMax={4}
fullWidth={true}
/>
</div>
<div className={classes.connPageButton}>
<Button type={"submit"} color="primary" variant="contained">Evaluate</Button> </div>
<div>
<MyTextField
variant="outlined"
margin="dense"
id="outputs.0"
name="outputs.0"
label="Output"
value={result}
multiline={true}
rowsMax={4}
fullWidth={true}
/>
</div>
</Form>
</Formik>
</Paper>
</Container>
);

React Material UI + Formik FieldArray Autocomplete control value stays same on remove

I want use Formik's form validation and it actually works just fine, but I ran into some issues with selected value display in Autocomplete component. I Have created Add/Remove buttons to dynamically adjust how many rows are in my form. The bug occurs when I try to remove form row, the row below, behind scenes has proper values as displayed in DEBUG, but user's input displays value from deleted form row. I cannot figure out, how to display or handle this occurrence.
Form before removal,
Form after removal
<FieldArray name="actions"
render={arrayHelpers =>
values.actions.map((action, index) => (
<Grid item container spacing={1} justify="center" alignItems="center"
key={index}>
<Grid item xs={4}>
<Field
error={getIn(errors, `actions.${index}.suggestedAction`) &&
getIn(touched, `actions.${index}.suggestedAction`)}
helperText={<ErrorMessage
name={`actions.${index}.suggestedAction`}/>}
name={`actions.${index}.suggestedAction`}
id={`actions.${index}.suggestedAction`}
variant="outlined"
fullWidth
as={TextField}
label="Siūloma priemonė"
multiline
rows={3}
rowsMax={10}
/>
</Grid>
<Grid item xs={4}>
<Autocomplete
freeSolo
onBlur={handleBlur}
onChange={(e, value) => {
//If adding new
if (value && value.inputValue) {
setOpen(true);
setFieldValue(`actions.${index}.responsiblePerson`, value.inputValue)
} else if (value && value.id) {
//Selecting existing
setFieldValue(`actions.${index}.responsiblePerson`, value.id)
} else {
setFieldValue(`actions.${index}.responsiblePerson`, "")
}
}}
getOptionLabel={(option) => {
if (typeof option === 'string') {
return option;
}
if (option.inputValue) {
return option.inputValue;
}
return option.title;
}}
handleHomeEndKeys
clearText="Pašalinti"
noOptionsText="Tuščia..."
renderOption={option => option.title}
filterOptions={(options, params) => {
const filtered = filter(options, params);
if (params.inputValue !== '') {
filtered.push({
inputValue: params.inputValue,
title: `Pridėti "${params.inputValue}"`,
});
}
return filtered;
}}
renderInput={params => (
<TextField
{...params}
id={`actions.${index}.responsiblePerson`}
name={`actions.${index}.responsiblePerson`}
error={getIn(errors, `actions.${index}.responsiblePerson`) &&
getIn(touched, `actions.${index}.responsiblePerson`)}
helperText={<ErrorMessage
name={`actions.${index}.responsiblePerson`}/>}
onChange={handleChange}
variant="outlined"
label="Atsakingas asmuo"
placeholder="Vardenis Pavardenis"
/>
)}
options={top100Films}/>
</Grid>
<DateTimeUtilsProvider>
<Grid item xs={3}>
<Field
disableToolbar
as={KeyboardDatePicker}
variant="inline"
inputVariant="outlined"
format="yyyy-MM-dd"
id={`actions.${index}.deadline`}
name={`actions.${index}.deadline`}
error={getIn(errors, `actions.${index}.deadline`) &&
getIn(touched, `actions.${index}.deadline`)}
helperText={<ErrorMessage
name={`actions.${index}.deadline`}/>}
label="Įvykdymo terminas"
onChange={value =>
setFieldValue(`actions.${index}.deadline`, value)}
/>
</Grid>
</DateTimeUtilsProvider>
<Grid item xs={1}>
<ButtonGroup fullWidth orientation="vertical" size="medium">
<Button onClick={() => {
arrayHelpers.remove(index);
}}
disabled={values.actions.length === 1}
classes={removeButtonClasses}>
<HighlightOff/>
</Button>
<Button onClick={() => {
arrayHelpers.insert(index + 1, {
suggestedAction: "",
responsiblePerson: "",
deadline: Date.now()
})
}}
color="primary">
<AddCircleOutline/>
</Button>
</ButtonGroup>
</Grid>
</Grid>
))
}
/>
</Grid>
Instead of
arrayHelpers.insert()
I have used
arrayHelpers.push()
and its working fine for me.
I had this same problem. I was setting a value prop on the <Field> inside my renderInput.
<Autocomplete
renderInput={params => (
<Field {...params} component={TextField} value={values.myArray[index]} />
)}
/>
I was able to fix it by moving the value attribute to the Autocomplete.
<Autocomplete
value={values.myArray[index]}
renderInput={params => (
<Field {...params} component={TextField} />
)}
...
/>
This worked for me
const arrayValue = options.filter(
(item) => item.id === values[arrayName][index][name]);
And then I used the filtered option as my value in the Autocomplete component
<Autocomplete
name={name}
value={arrayValue.length > 0 ? arrayValue[0] : null}
options={options}
groupBy={(option) => option.group}
getOptionLabel={(option) => option.value}
isOptionEqualToValue={(option, value) => option?.id === value?.id}
defaultValue={defaultValueCheck()}
onChange={(_, value) => {
setFieldValue(`${arrayName}[${index}].${name}`, value?.id ?? "");
}}
renderInput={(params) => (
<TextField
{...params}
{...configTextField}
name={`${arrayName}[${index}].${name}`}
/>
)}
renderGroup={(params) => (
<li key={params.key}>
<GroupHeader>{params.group}</GroupHeader>
<GroupItems>{params.children}</GroupItems>
</li>
)}
/>
</>

Ant design <Form.List> create static array of forms

I am using antd with react to develop an application.
<Form.List name="secondaryContacts">
{(fields, { add, remove }) => {
return (
<div>
{fields.map((field, index) => (
<Form.Item
{...formItemLayoutWithOutLabel}
label={index === 0 ? "" : ""}
required={false}
key={field.key}
>
<Form.Item
{...field}
validateTrigger={["onChange", "onBlur"]}
rules={[
{
required: true,
validator: phoneNumberValidator
}
]}
>
<Input
placeholder="Secondary Contact"
addonAfter={
fields.length >= 1 ? (
<MinusCircleOutlined
onClick={() => {
remove(field.name);
}}
/>
) : null
}
/>
</Form.Item>
</Form.Item>
))}
<Form.Item {...formItemLayoutWithOutLabel}>
<Button
type="dashed"
onClick={() => {
add();
}}
style={{ width: "100%" }}
>
<PlusOutlined /> Add Secondary Contact
</Button>
</Form.Item>
</div>
);
}}
</Form.List>;
Above is the code I am using to add dynamic form fields with validation using Form.List.
Now I have a specific scenario where I need to show 7 Sliders(https://ant.design/components/slider/) for the selected time slot and store them in an array, so I thought of using Form.List and keep all sliders inside just like above(except that it's static).
But I am not clear how I can achieve it with Form.List and there are very few examples on the internet.
I have a scenario where I need to have an array of forms and club them as an array using Form.List.
You can use the initialValue property to set the static data
Example:
const staticValue = [{ formItem1: 'value1', formItem2: 'value2'}];
<Form.List name="formListName" initialValue={staticValue}>
{(fields, { add, remove }, { errors }) => (
fields.map((field) => (
<>
<Form.Item {...field} name={[field.name, 'formItem1']}>
<Input placeholder="Field 1" />
</Form.Item>
...
You still need <Form> component
Try
<Form>
<Form.List>
</Form.List>
</Form>

Any way to render Icon based on text field name using material UI?

<TextField
margin='dense'
fullWidth
value={this.props.value}
name={this.props.name}
type={this.props.type}
error={this.props.error !== ''}
helperText={this.props.error !== '' ? this.props.error : ' '}
onChange={ e => this.handleChange(e) }
label={this.props.label}
variant= {this.props.variant}
id={this.props.name}
InputProps={{
endAdornment: (
<AccountCircle />
),
}}
/>
Is there any way to display different Icons based on Text field name? I mean, If the name is Email then display EmailIcon. If profile then displays AccountCircle.
here is a simple solution so you can start it from here
let icon = null;
if (this.props.name === "Password") {
icon = <Visibility />;
} else if (this.props.name === "Account") {
icon = <AccountCircle />;
}
return (
<div className={classes.root}>
<TextField
label={this.props.name}
className={classNames(classes.margin, classes.textField)}
InputProps={{
endAdornment: icon
}}
/>
</div>
);
here I have put the name as a prop in this component and depend on that prop I change the icon. you can change this to switch if you wish.
hope you got an idea.
here is a link of a demo: https://codesandbox.io/s/moo68122lp
You can do it in an elegant way, by abstracting like this:
import { AccountCircle, UserIcon, PhoneIcon } from 'some/ui/library';
const icons = {
account: AccountCircle,
user: UserIcon,
phone: PhoneIcon,
};
const FieldIcon = ({ name }) => {
const Icon = icons[name];
return Icon ? (<Icon />) : null;
};
const YourComponent = props => (
<TextField
margin='dense'
fullWidth
value={props.value}
name={props.name}
type={props.type}
error={props.error !== ''}
helperText={props.error !== '' ? props.error : ' '}
label={props.label}
variant= {props.variant}
id={props.name}
InputProps={{
endAdornment: (
<FieldIcon name={props.name} />
),
}}
/>
);

Resources