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

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

Related

Button to view update logo

Whenever the page loads, it should load a different logo, but when I click on the icon to view the password in the PASSWORD field, it reloads the logo.
I tried to leave asynchronously but it was not the case, maybe it's a problem with react hooks
export default function Login() {
const [showPassword, setShowPassword] = React.useState(false);
const handleClickShowPassword = () => setShowPassword((show) => !show);
const handleMouseDownPassword = (
event: React.MouseEvent<HTMLButtonElement>
) => {
event.preventDefault();
};
const logo = (): string => {
switch (parseInt((Math.random() * (4 - 1) + 1).toString(), 10)) {
case 1:
return "/logo4.png";
case 2:
return "/logo2.png";
case 3:
return "/logo3.png";
default:
return "/logo3.png";
}
};
return (
<Image
src={logo().toString()}
width={150}
height={150}
alt="Página de login"
></Image>
<br />
<FormControl sx={{ m: 1, width: "25ch" }} variant="outlined">
<InputLabel htmlFor="outlined-adornment-password">
Senha
</InputLabel>
<OutlinedInput
id="outlined-adornment-password"
type={showPassword ? "text" : "password"}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{showPassword ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
}
label="Senha"
placeholder="**********"
/>
</FormControl>
);
}
The expectation is not to load the logo function when clicking to view the password

Using React Hook Form with other component

I want to create dynamic form with react-hook-form.
Below is my code.
I want to create a dialog for entering a detailed profile in a separate component and use it in MainForm.
I can display the DetailForm, but the values entered in it are not reflected.
Data on the DetailForm component is not included when submitting.
Any guidance on how to do this would be greatly appreciated.
MainForm
import React from 'react';
import {
useForm,
Controller,
useFieldArray
} from 'react-hook-form';
import {
Button,
TextField,
List,
ListItem,
IconButton,
} from '#material-ui/core';
import DetailForm from '#components/DetailForm'
import AddCircleOutlineIcon from '#material-ui/icons/AddCircleOutline';
function MainForm(props:any) {
const { control, handleSubmit, getValues } = useForm({
mode: 'onBlur',
defaultValues: {
profiles: [
{
firstName: '',
lastName: '',
email: '',
phone: ''
}
]
}
});
const { fields, append, remove } = useFieldArray({
control,
name: 'profiles',
});
const onSubmit = () => {
const data = getValues();
console.log('data: ', data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<List>
fields.map((item, index) => {
return (
<ListItem>
<Controller
name={`profiles.${index}.firstName`}
control={control}
render={({field}) =>
<TextField
{ ...field }
label="First Name"
/>
}
/>
<Controller
name={`profiles.${index}.lastName`}
control={control}
render={({field}) =>
<TextField
{ ...field }
label="Last Name"
/>
}
/>
<DetailForm index={index} />
</ListItem>
)
})
</List>
<IconButton onClick={() => append({})}>
<AddCircleOutlineIcon />
</IconButton>
<Button
type='submit'
>
SAVE
</Button>
</form>
)
}
DetailForm
import React from 'react';
import {
Button,
TextField,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
} from '#material-ui/core';
export default function DetailForm(props: any) {
const [dialogState, setDialogState] = React.useState<boolean>(false);
const handleOpen = () => {
setDialogState(true);
};
const handleClose = () => {
setDialogState(false);
};
return (
<>
<Button
onClick={handleOpen}
>
Set Detail Profile
</Button>
<Dialog open={dialogState}>
<DialogTitle>Detail Profile</DialogTitle>
<DialogContent>
<TextField
name={`profiles.${props.index}.email`}
label="Email Address"
/>
<TextField
name={`profiles.${props.index}.phone`}
label="Phone Number"
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>
Cancel
</Button>
<Button onClick={handleClose}>
Add
</Button>
</DialogActions>
</Dialog>
</>
)
}
You have to register those fields inside your <Dialog /> component - just pass control to it. It's also important to set an inline defaultValue when using <Controller /> and useFieldArray. From the docs:
inline defaultValue is required when working with useFieldArray by integrating with the value from fields object.
One other minor thing: You should also pass the complete fieldId to your <Dialog /> component instead of just passing the index. This way it would be easier to change the fieldId in one place instead of editing all fields in your <Dialog /> component.
MainForm
<ListItem key={item.id}>
<Controller
name={`profiles.${index}.firstName`}
control={control}
defaultValue=""
render={({ field }) => (
<TextField {...field} label="First Name" />
)}
/>
<Controller
name={`profiles.${index}.lastName`}
control={control}
defaultValue=""
render={({ field }) => (
<TextField {...field} label="Last Name" />
)}
/>
<DetailForm control={control} fieldId={`profiles.${index}`} />
</ListItem>
DetailForm
export default function DetailForm({ control, fieldId }) {
const [dialogState, setDialogState] = React.useState(false);
const handleOpen = () => {
setDialogState(true);
};
const handleClose = () => {
setDialogState(false);
};
return (
<>
<Button onClick={handleOpen}>Set Detail Profile</Button>
<Dialog open={dialogState}>
<DialogTitle>Detail Profile</DialogTitle>
<DialogContent>
<Controller
name={`${fieldId}.email`}
control={control}
defaultValue=""
render={({ field }) => (
<TextField {...field} label="Email Address" />
)}
/>
<Controller
name={`${fieldId}.phone`}
control={control}
defaultValue=""
render={({ field }) => (
<TextField {...field} label="Phone Number" />
)}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Cancel</Button>
<Button onClick={handleClose}>Add</Button>
</DialogActions>
</Dialog>
</>
);
}

How to use InputProps of TextField in <input /> element

Is there any way to use the InputProps in <input /> element instead of <TextField /> of Material UI?
My Input.js component where I have used InputProps:
const Input = ({name, handleChange, type, handleShowPassword}) => {
return(
<input
name={name}
onChange={handleChange}
require
type={type}
InputProps={name === 'password' && {
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={handleShowPassword}>
{type === 'password' ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
),
}}
/>
)
}
export default Input
SignUp.js:
const SignUp = () => {
return (
<div>
<Input name="firstName" handleChange={handleChange} />
<Input name="password" type={showPassword ? 'text' : 'password'} handleShowPassword={handleShowPassword} />
</div>
)
}
export default SignUp
Please any help would be appreciated or feel free to share if there are any other ways to achieve the result.
My suggestion is you need to use Tailwindcss, and install tailwindcss/forms package.
I just found one tailwind component that are using
<input/>
for that functionality.
Here's the link for that : https://www.hyperui.dev/components/marketing/forms

How to mask material ui input in formic with using react-input-mask (typescript)

Input in formik
Error in type of TextField
<InputMask
mask="99/99/9999"
value={formik.values.phone}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
>
{(inputProps: Props): ReactElement => (
<TextField
{...inputProps}
type="tel"
label={t("addDriverModal.phone")}
/>
)}
</InputMask>
Does not work. Props - type declaration from #types/react-input-mask
import { TextField, TextFieldProps } from "#material-ui/core";
import InputMask, {Props} from 'react-input-mask';
<InputMask
mask="99/99/9999"
value={formik.values.phone}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
>
{/*
'props' supplied to TextField weren't matching the required type.
Hence we use '&' operator which is for intersecting two types
*/}
{(inputProps: Props & TextFieldProps)=>
<TextField
{...inputProps}
type="tel"
label={t("addDriverModal.phone")}
/>
}
</InputMask>
I'm not sure how it works in TypeScript but you can do this.
/* Create Your Mask Component Like This */
const phoneMaskComponent = arg => {
const { inputRef, ...other } = arg;
const digitRegExp = /[0-9٠-٩۰-۹]/;
return (
<MaskedInput
ref={ref => {
inputRef(ref ? ref.inputElement : null);
}}
guide={false}
mask={strNumber => {
return strNumber.split('').map(() => {
return digitRegExp;
});
}}
pipe={str => {
const newStr = str
.replace(/[٠١٢٣٤٥٦٧٨٩]/g, d => d.charCodeAt(0) - 1632)
.replace(/[۰۱۲۳۴۵۶۷۸۹]/g, d => d.charCodeAt(0) - 1776)
.replace(/[^0-9]+/g, '');
return {
value: newStr,
indexesOfPipedChars: range(newStr.length * 2),
};
}}
{...other}
/>
);
};
/* Set The Mask in Your Input Component */
<InputBase
fullWidth
isLtr
name="phone"
label="Enter Phone Number"
type="tel"
value={formik.values.phone}
/* Use The Mask like This */
inputComponent={phoneMaskComponent}
/>
this mask dose not let user to enter En numbers.
i done that way and it works for me:
const MYInput = ({...props}) => (
<Field
name={props.name}
render={({field}) => {
return (
<InputMask
{...field}
mask={props.mask}
>
{(innerProps) => (
<TextField
{...innerProps}
variant={props.variant ? props.variant : 'filled'}
label={props.label ? props.label : ''}
/>
)}
</InputMask>
)
}}
/>
);
<MYInput name="Phone" label="Phone" mask="(99) 99999-9999" />

how to edit a textfield values in reactjs

Here i add my sample code.i have a static values getting from state now i want to change this values
render() {
console.log(this.props.selectedVal);
var name,
gender,
city = "";
this.props.data.map((row, index) => {
// console.log(index);
if (this.props.selectedVal === index) {
gender = row[0];
name = row[1];
city = row[2];
}
return [];
});
return (
<Dialog
open={this.props.open}
onClose={this.handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<h1>Edit User</h1>
<DialogContent>
<DialogContentText id="alert-dialog-description" />
<Formik
initialValues={{ name: "", gender: "", city: "" }}
onSubmit={values => console.log(values)}
>
{props => (
<form>
<TextField margin="dense" id="name" label="Name" value={name} />
<br />
<TextField
margin="dense"
id="gender"
label="Gender"
value={gender}
/>
<br />
<TextField margin="dense" label="City" value={city} />
</form>
)}
</Formik>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClose} color="primary">
RESET
</Button>
<Button onClick={this.handleClose} color="primary" autoFocus>
SUBMIT
</Button>
</DialogActions>
</Dialog>
);
}
I am getting the values from the table row.Now i want to change these values using formik. How can I edit these values
Add a onChange listener in your textfield and map the value to a state variable:
textChange(e) {
const value = e.target.value
this.setState({ value })
}
render() {
return (
<TextField value={this.state.value} onChange={this.textChange} .. />
)
}
If you want to handle more values from different textfields using one method try something like this:
textChange(e) {
const id = e.target.id
const value = e.target.value
this.setState({ [id]: value })
}
render() {
return (
<TextField id="gender" value={this.state.gender} onChange={this.textChange} .. />
<TextField id="dense" value={this.state.dense} onChange={this.textChange} .. />
)
}
It seems like you get data with props from parent component. And, if I get it wright, question is how to change state of parent component? You need to add to props function binded to parent`s context and use setState there.

Resources