I'm sending my react-hook-form field to another function component as a children. After pressing Submit Button, the field refreshes and the value inputed is deleted. What is the problem?
CodeSandBox example is here
My file App.js:
import React from "react";
import "./styles.css";
import { useForm } from "react-hook-form";
import { Box, Button, Grid, TextField } from "#material-ui/core";
export default function App() {
const { register, handleSubmit } = useForm();
function onSubmit(data) {
console.log(data);
}
function FieldComponent(props) {
const { title, children } = props;
return (
<Grid container alignItems="center">
<Grid item xs={3}>
<Box py={5}>
<div fontWeight="bold" fontSize="16">
{title}
</div>
</Box>
</Grid>
<Grid item xs={9}>
<Box py={5}>{children}</Box>
</Grid>
</Grid>
);
}
return (
<div className="App">
<Grid container>
<Grid item xs={12}>
<FieldComponent title="name">
<TextField variant="outlined" name="name" inputRef={register} />
</FieldComponent>
</Grid>
<Grid item xs={12}>
<Button variant="outlined" onClick={handleSubmit(onSubmit)}>
Submit
</Button>
</Grid>
</Grid>
</div>
);
}
It's always a good idea to move your sub-component into its own, otherwise, each re-render will mount and unmount your component.
function FieldComponent(props) {
const { title, children } = props;
return (
<Grid container alignItems="center">
<Grid item xs={3}>
<Box py={5}>
<div fontWeight="bold" fontSize="16">
{title}
</div>
</Box>
</Grid>
<Grid item xs={9}>
<Box py={5}>{children}</Box>
</Grid>
</Grid>
);
}
export default function App() {
const { register, handleSubmit } = useForm();
function onSubmit(data) {
console.log(data);
}
return (
<div className="App">
<Grid container>
<Grid item xs={12}>
<FieldComponent title="name">
<TextField variant="outlined" name="name" inputRef={register} />
</FieldComponent>
</Grid>
<Grid item xs={12}>
<Button variant="outlined" onClick={handleSubmit(onSubmit)}>
Submit
</Button>
</Grid>
</Grid>
</div>
);
}
https://codesandbox.io/s/agitated-darkness-leg7z?file=/src/App.js
Related
I'm new to reactjs. I have created a dropdown for a company list and want to get values. I still couldn't be able to get values from the dropdown. I've tried several methods of retrieving data but not able to do that. can anyone help me to get values? Here is some of my code.
<Grid container spacing={3}>
<Grid item xs={12} sm={6}>
<SoftBox mb={1} ml={0.5} lineHeight={0} display="inline-block">
<SoftTypography
component="label"
variant="caption"
fontWeight="bold"
textTransform="capitalize">
Country
</SoftTypography>
</SoftBox>
<Select input={<SoftInput />} value={country} onChange={handleSetCountry}>
<MenuItem value="...">country</MenuItem>
<MenuItem value="10">Hello 10</MenuItem>
<MenuItem value="11">Hello 11</MenuItem>
<MenuItem value="12">Hello 12</MenuItem>
</Select>
</Grid>
Here is my whole code.
/**
=========================================================
* Soft UI Dashboard PRO React - v4.0.0
=========================================================
* Product Page: https://material-ui.com/store/items/soft-ui-pro-dashboard/
* Copyright 2022 Creative Tim (https://www.creative-tim.com)
Coded by www.creative-tim.com
=========================================================
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
import { useState } from "react";
// prop-type is a library for typechecking of props
import PropTypes from "prop-types";
// #mui material components
import Grid from "#mui/material/Grid";
import Select from "#mui/material/Select";
import MenuItem from "#mui/material/MenuItem";
// Soft UI Dashboard PRO React components
import Switch from "#mui/material/Switch";
import SoftBox from "components/SoftBox";
import SoftTypography from "components/SoftTypography";
import SoftInput from "components/SoftInput";
// NewUser page components
import FormField from "layouts/pages/new/new-company/components/FormField";
import { DateTimePicker } from "#material-ui/pickers";
import { distance } from "chroma-js";
function General({ formData }) {
const [country, setCountry] = useState("...");
const handleSetCountry = (event) => setCountry(event.target.value);
const { formField, values, errors, touched } = formData;
const { comNumber, address1, address2, city, state, postcode, additional, phone, phone1, fax, web } = formField;
const { comNumber: comNumberV, address1: address1V, address2: address2V, city: cityV, state: stateV, postcode: postcodeV, additional: additionalV,
phone: phoneV, phone1: phone1V, fax: faxV, web: webV} = values;
const [selectedDate, handleDateChange] = useState(new Date());
const [rememberMe, setRememberMe] = useState(false);
const handleSetRememberMe = () => setRememberMe(!rememberMe);
return (
<SoftBox>
<SoftTypography variant="h5" fontWeight="bold">
General
</SoftTypography>
<SoftBox mt={1.625}>
<Grid container spacing={3}>
<Grid item xs={12} sm={6}>
<FormField
type={comNumber.type}
label={comNumber.label}
name={comNumber.name}
value={comNumberV}
placeholder={comNumber.placeholder}
error={errors.comNumber && touched.comNumber}
success={comNumberV.length > 0 && !errors.comNumber}
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormField
type={address1.type}
label={address1.label}
name={address1.name}
value={address1V}
placeholder={address1.placeholder}
/>
</Grid>
</Grid>
<Grid container spacing={3}>
<Grid item xs={12} sm={6}>
<FormField
type={address2.type}
label={address2.label}
name={address2.name}
value={address2V}
placeholder={address2.placeholder}
/></Grid>
<Grid item xs={12} sm={6}>
<FormField
type={city.type}
label={city.label}
name={city.name}
value={cityV}
placeholder={city.placeholder}
/>
{/* <FormField
type={city.type}
label={city.label}
name={city.name}
value={cityV}
placeholder={city.placeholder}
error={errors.city && touched.city}
success={cityV.length > 0 && !errors.city}
/> */}
</Grid>
</Grid>
{/* <Grid item xs={6} sm={3}>
<SoftBox mb={1} ml={0.5} lineHeight={0} display="inline-block">
<SoftTypography
component="label"
variant="caption"
fontWeight="bold"
textTransform="capitalize"
>
State
</SoftTypography>
</SoftBox>
<Select input={<SoftInput />} value={state} onChange={handleSetState}>
<MenuItem value="...">state</MenuItem>
<MenuItem value="10">Hello 10</MenuItem>
<MenuItem value="11">Hello 11</MenuItem>
<MenuItem value="12">Hello 12</MenuItem>
</Select>
</Grid>
<Grid item xs={6} sm={3}>
<FormField
type={zip.type}
label={zip.label}
name={zip.name}
value={zipV}
placeholder={zip.placeholder}
error={errors.zip && touched.zip}
success={zipV.length > 0 && !errors.zip}
/>
</Grid>
</Grid> */}
<Grid container spacing={3}>
<Grid item xs={12} sm={6}>
<FormField
type={state.type}
label={state.label}
name={state.name}
value={stateV}
placeholder={state.placeholder}
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormField
type={postcode.type}
label={postcode.label}
name={postcode.name}
value={postcodeV}
placeholder={postcode.placeholder}
error={errors.postcode && touched.postcode}
success={postcodeV.length > 0 && !errors.postcode}
/>
</Grid>
</Grid>
<Grid container spacing={3}>
<Grid item xs={12} sm={6}>
<SoftBox mb={1} ml={0.5} lineHeight={0} display="inline-block">
<SoftTypography
component="label"
variant="caption"
fontWeight="bold"
textTransform="capitalize">
Country
</SoftTypography>
</SoftBox>
<Select input={<SoftInput />} value={country} onChange={handleSetCountry}>
<MenuItem value="...">country</MenuItem>
<MenuItem value="10">Hello 10</MenuItem>
<MenuItem value="11">Hello 11</MenuItem>
<MenuItem value="12">Hello 12</MenuItem>
</Select>
</Grid>
<Grid item xs={12} sm={6}>
<FormField
type={additional.type}
label={additional.label}
name={additional.name}
value={additionalV}
placeholder={additional.placeholder}
/>
</Grid>
</Grid>
<Grid container spacing={3}>
<Grid item xs={12} sm={6}>
<FormField
type={phone.type}
label={phone.label}
name={phone.name}
value={phoneV}
placeholder={phone.placeholder}
error={errors.phone && touched.phone}
success={phoneV.length > 0 && !errors.phone}
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormField
type={phone1.type}
label={phone1.label}
name={phone1.name}
value={phone1V}
placeholder={phone1.placeholder}
error={errors.phone1 && touched.phone1}
success={phone1V.length > 0 && !errors.phone1}
/>
</Grid>
</Grid>
<Grid container spacing={3}>
<Grid item xs={12} sm={6}>
<FormField
type={fax.type}
label={fax.label}
name={fax.name}
value={faxV}
placeholder={fax.placeholder}
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormField
type={web.type}
label={web.label}
name={web.name}
value={webV}
placeholder={web.placeholder}
/>
</Grid>
</Grid>
{/* <Grid container spacing={3}>
<Grid item xs={12} >
<FormField
type={distance.type}
label={distance.label}
name={distance.name}
value={distanceV}
placeholder={distance.placeholder}
/>
</Grid>
</Grid>
<SoftBox display="flex" alignItems="center">
<Switch checked={rememberMe} onChange={handleSetRememberMe} />
<SoftTypography
variant="button"
fontWeight="regular"
onClick={handleSetRememberMe}
sx={{ cursor: "pointer", userSelect: "none" }}
>
Company Opted Out From Surveys
</SoftTypography>
</SoftBox> */}
</SoftBox>
</SoftBox>
);
}
// typechecking props for Address
General.propTypes = {
formData: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired,
};
export default General;
I need to get dropdown values. Can anyone help me to solve this?
First of all, you should really create a small example in Codesandbox and post it here...
Anyway,
As far as I can see you have two different dropdowns/select components (state and country).
You get no value from neither of them ? The Country one seems to be okay, but the State is missing its event handler (?).
What does a simple console.log output show?:
const handleSetCountry = (event) => {
console.log(event.target.value);
setCountry(event.target.value);
}
Also, try without the
input={<SoftInput />}
and see what happens
I have 3 components on my react page
PageHeader,SideMenu & FeatureList (which is made up of Display Cards) here are the components below:-
App.js
import './App.css';
import { Grid } from '#mui/material';
import SideMenu from './components/home/SideMenu';
import Features from './components/home/Features';
import PageHeader from './components/home/PageHeader';
function App() {
return (
<Grid container spacing={10}>
<Grid item xs={3}>
<PageHeader></PageHeader>
<SideMenu></SideMenu>
</Grid>
<Grid item xs={8}>
<Features></Features>
</Grid>
</Grid>
// <div>
// <PageHeader></PageHeader>
// <SideMenu></SideMenu>
// <Features></Features>
// </div>
);
}
export default App;
PageHeader.js
import * as React from 'react';
import AppBar from '#mui/material/AppBar';
import Box from '#mui/material/Box';
import Toolbar from '#mui/material/Toolbar';
import Typography from '#mui/material/Typography';
import Button from '#mui/material/Button';
import IconButton from '#mui/material/IconButton';
import MenuIcon from '#mui/icons-material/Menu';
import { Grid } from '#mui/material';
var LOGGED_IN = false
const getButtons = (LOGGED_IN) => {
if (LOGGED_IN) {
return <Grid container>
<Grid item xs={7}></Grid>
<Grid item xs={2} >
<Button color="inherit">
<Typography variant="h6" component="div">
Profile
</Typography>
</Button>
</Grid>
<Grid item xs={2} >
<Button color="inherit">
<Typography variant="h6" component="div">
Logout
</Typography>
</Button>
</Grid>
</Grid>
}
else
return <Grid container>
<Grid item xs={9}></Grid>
<Grid item xs={2}>
<Button color="inherit">
<Typography variant="h6" component="div">
Login
</Typography>
</Button>
</Grid>
</Grid>
}
const drawerWidth = 240
export default function PageHeader(props) {
return (
<Grid item container>
<Grid container>
<AppBar
sx={{
width: { sm: `calc(100% - ${drawerWidth}px)` },
ml: { sm: `${drawerWidth}px` },
}}
>
<Toolbar>
<Grid item xs={4}>
<Typography variant="h3" component="div">
Stonks!
</Typography>
</Grid>
{getButtons(LOGGED_IN)}
</Toolbar>
</AppBar>
</Grid>
</Grid>
);
}
SideMenu.js
import * as React from 'react';
import { Divider, Drawer, Grid, List, ListItem, ListItemIcon, ListItemText } from '#mui/material';
import { styled, useTheme } from '#mui/material/styles';
import BusinessIcon from '#mui/icons-material/Business';
import ShowChartIcon from '#mui/icons-material/ShowChart';
import AppsIcon from '#mui/icons-material/Apps';
import SupervisedUserCircleIcon from '#mui/icons-material/SupervisedUserCircle';
import InfoIcon from '#mui/icons-material/Info';
import CreateIcon from '#mui/icons-material/Create';
const DrawerHeader = styled('div')(({ theme }) => ({
...theme.mixins.toolbar,
}))
const drawerWidth = 240
export default function SideMenu(props) {
const theme = useTheme();
const [open, setOpen] = React.useState(true)
const handleDrawerOpen = () => {
setOpen(true)
}
const handleDrawerClose = () => {
setOpen(false)
}
return (
<Grid container spacing={2}>
<Grid item xs={12} container direction="column">
<Drawer
sx={{
width: drawerWidth,
flexShrink: 0,
boxSizing: 'border-box',
'& .MuiDrawer-paper': {
width: drawerWidth,
boxSizing: 'border-box',
},
}}
variant="persistent"
anchor="left"
open={true}
>
<Grid item xs={0} container display='flex' alignItems='center' justifyContent='flex-end'>
<DrawerHeader display='flex'>
</DrawerHeader>
</Grid>
<Grid item xs={0}>
<Divider />
</Grid>
<Grid item container direction='column'>
<List>
{
['Companies', 'Exchanges', 'Sectors', 'Users'].map((text) => (
<Grid item xs={12}>
<ListItem button key={text}>
<ListItemIcon>
{(() => {
switch (text) {
case 'Companies':
return <BusinessIcon />
case 'Exchanges':
return <ShowChartIcon />
case 'Sectors':
return <AppsIcon />
case 'Users':
return <SupervisedUserCircleIcon />
}
})()}
{/* <MenuIcon /> */}
</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
</Grid>
))
}
</List>
</Grid>
<Grid item>
<Divider />
</Grid>
<Grid item container direction='column'>
<List>
{
['About', 'Creators'].map((text) => (
<Grid item xs={12}>
<ListItem button key={text}>
<ListItemIcon>
{(() => {
switch (text) {
case 'About':
return <InfoIcon />
case 'Creators':
return <CreateIcon />
}
})()}
{/* <MenuIcon /> */}
</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
</Grid>
))
}
</List>
</Grid>
</Drawer>
</Grid>
</Grid>
);
}
Features.js
import { Grid } from "#mui/material";
import React from "react";
import DisplayCard from "./DisplayCard";
import company from '../../static/company.jpg'
import stock_exchange from '../../static/stock_exchange.jpg'
import sector from '../../static/sector.png'
import user from '../../static/user.png'
export default function Features(props) {
return (
<Grid container spacing={3}>
<Grid item md={3}>
<DisplayCard name="Companies" brief="View All the Registerd Companies and Click on them to explore each of them in
detail" image={company}></DisplayCard>
</Grid>
<Grid item md={3}>
<DisplayCard name="Stock Exchanges" brief="View All the Registerd Stock Exchanges and Click on them to explore each of them in
detail" image={stock_exchange}></DisplayCard>
</Grid>
<Grid item md={3}>
<DisplayCard name="Sectors" brief="View All the Registerd Sectors and Click on them to explore each of them in
detail" image={sector}></DisplayCard>
</Grid>
<Grid item md={3}>
<DisplayCard name="Users" brief="View All the Registerd Users and Click on them to explore each of them in
detail" image={user}></DisplayCard>
</Grid>
</Grid>
)
}
DispalyCard.js
import React from "react";
import Card from '#mui/material/Card';
import CardContent from '#mui/material/CardContent';
import CardMedia from '#mui/material/CardMedia';
import Typography from '#mui/material/Typography';
import { Button, CardActionArea, CardActions, Grid } from '#mui/material';
export default function DisplayCard(props) {
return (
<Grid container spacing={2}>
<Card sx={{ border: "groove", maxWidth: 300, maxHeight: 400 }}>
<CardActionArea >
<Grid item xs={12}>
<CardMedia
component='img'
height='140'
image={props.image}
width='inherit'
/>
</Grid>
<Grid item container>
<CardContent>
<Grid item xs={12}>
<Typography gutterBottom variant='h4' component='div'>
{props.name}
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant='body2' color='text.secondary'>
{props.brief}
</Typography>
</Grid>
</CardContent>
</Grid>
</CardActionArea>
<Grid>
<CardActions>
<Button size='small' color='primary'>
Click Here
</Button>
</CardActions>
</Grid>
</Card >
</Grid >
);
}
Currently my output is
As u can see the Feature Cards are getting overlapped by the Header
I want to make them not overlap but I have tried a lot of things but as I am a beginner in Grid & Flexbox im not able to make it correct
Any help will be appreciated.
It looks like you have your header set to position: fixed which removes it from the normal flow of the page. There may be a more elegant solution but so far the best solution for me has been adding the following to my CSS:
body {
padding-top: *height of header*;
}
I'm having an issue with the latest version of Mui. I'm using a Theme to change the default styling of a text field input the error code has something to do with "./node_modules/#mui/material/FormLabel/FormLabel.js/FormLabelRoot<" I've got the following dependencies
"#emotion/react": "^11.4.1",
"#emotion/styled": "^11.3.0",
"#mui/icons-material": "^5.0.1",
"#mui/material": "^5.0.1",
If anyone has an idea I'd love to hear it :)
import React, { useState } from "react"
import { Button, createTheme, Grid, TextField, Tooltip } from "#mui/material"
import { ThemeProvider } from "#mui/system"
import { AddRounded, CalendarToday, Phone, Email, SearchOutlined, People, Work } from "#mui/icons-material"
import { orange } from "#mui/material/colors"
function App() {
//logic
const [contacts, setContacts] = useState([])
const [addFormData, setAddFormData] = useState({
name: "", email: "", phone: "", dateCreated: "", area: ""
})
/* search reflects the value of the googleesque, search bar. */
const [search, setSearch] = useState("")
/* refrlcts the */
const [searchResults, setSearchResults] = useState([])
const handleAddFormChange = (e) => {
e.preventDefault()
const fieldName = e.target.getAttribute("name")
console.log(fieldName)
let fieldValue = e.target.value
console.log(fieldValue)
const newFormData = { ...addFormData }
newFormData[fieldName] = fieldValue
setAddFormData(newFormData)
}
const handleAddFormSubmit = (e) => {
e.preventDefault()
const newContact = {
name: addFormData.name,
email: addFormData.email,
phone: addFormData.phone,
dateCreated: addFormData.dateCreated,
area: addFormData.area,
split: addFormData.split
}
const newContacts = [...contacts, newContact]
setContacts(newContacts)
}
const handleSearch = (e) => {
e.preventDefault()
setSearch(e.target.value)
if (search !== "") {
const newContactList = contacts.filter((contact) => {
console.log(Object.values(contact).join(" ").toLowerCase())
return Object.values(contact).join(" ").toLowerCase().includes(search.toLowerCase())
})
console.log(search)
console.log(Object.values(contacts).join(" ").toLowerCase())
setSearchResults(newContactList)
} else {
setSearchResults(contacts)
}
}
const theme = createTheme({
palette: {
primary: {
// Purple and green play nicely together.
main: orange[500],
},
},
});
return (
<>
<ThemeProvider theme={theme}>
<Grid container spacing={1} alignItems="center" >
<Grid item>
<SearchOutlined />
</Grid>
<Grid item style={{ marginBottom: "15px", marginTop: "15px" }} >
<TextField type="text" variant="outlined" label="Search" onChange={handleSearch} />
</Grid>
</Grid>
<div >
{/* Main Container with soacing between pairs set to (3) */}
<Grid container spacing={3} >
{/* First pair, people icon + name input */}
<Grid item>
<Grid container spacing={1} alignItems="center">
<Grid item>
{/* icon */}
<Tooltip title="Name" placement="bottom" arrow>
<People />
</Tooltip>
</Grid>
<Grid item>
{/* input */}
<TextField label="Name" variant="outlined" id="name" name="name" type="text" onChange={handleAddFormChange} />
</Grid>
</Grid>
</Grid>
{/* Second pair */}
<Grid item>
<Grid container spacing={1} alignItems="center">
<Grid item>
{/* icon */}
<Tooltip title="what's your name" placement="bottom" arrow>
<Work />
</Tooltip>
</Grid>
<Grid item>
{/* Input */}
<TextField label="Area" variant="outlined" color="colME" id="area" name="area" type="text" onChange={handleAddFormChange} />
</Grid>
</Grid>
</Grid>
{/* Third Pair */}
<Grid item>
<Grid container spacing={1} alignItems="center">
<Grid item>
{/* Icon */}
<Tooltip title="name#example.com" placement="bottom" arrow>
<Email />
</Tooltip>
</Grid>
<Grid item>
{/* input */}
<TextField label="Email" variant="outlined" id="email" name="email" type="text" onChange={handleAddFormChange} />
</Grid>
</Grid>
</Grid>
<Grid item>
<Grid container spacing={1} alignItems="center">
<Grid item>
{/* Icon */}
<Tooltip title="Ex:(0049)15208513630" placement="bottom" arrow>
<Phone />
</Tooltip>
</Grid>
<Grid item>
{/* Input */}
<TextField label="phone" variant="outlined" id="dateCreated" name="phone" type="text" onChange={handleAddFormChange} />
</Grid>
</Grid>
</Grid>
<Grid item>
<Grid container spacing={1} alignItems="center">
<Grid item>
{/* Icon */}
<Tooltip title="Format:dd/mm/yyyy" placement="bottom" arrow>
<CalendarToday />
</Tooltip>
</Grid>
<Grid item>
{/* Input */}
<TextField label="Date" variant="outlined" id="dateCreated" name="dateCreated" type="text" onChange={handleAddFormChange} />
</Grid>
</Grid>
</Grid>
</Grid>
<Button style={{ marginBottom: "15px", marginTop: "15px", }} onClick={handleAddFormSubmit} variant="contained" startIcon={<AddRounded />}>
Add
</Button>
</div>
</ThemeProvider>
{/* if there less than 1 character in the search bar render the normal contacts, if not render only the contacts that match the search input... */}
{/* <ContactList contacts={search.length < 1 ? contacts : searchResults} key={contacts.id} /> */}
</>
);
}
export default App;
OP solved their problem, but for those like me that had a similar issue, be sure to check these few things. I'm experiencing these issues since I've upgraded our code-base to the latest version of Material UI.
The issue appears when you use a color or variant prop value not supported in a given component, usually Button, IconButton, or TextField.
Previously color="default" was just fine, but I realized that default was no longer supported. It's current equivalent is inherit.
If you want to support a custom color, you can create a theme that supports that. Read here: Adding new colors (mui.com)
I want to change the paragraph element with className="details" to an input field(editable) when user clicks on className="edit-icon" image within same grid container. How could I do that ?
import React from 'react';
import Grid from '#material-ui/core/Grid';
const Settings = () => {
return (
<div>
<Grid container>
<Grid item xs={4}>
<p className="details-label">NAME</p>
</Grid>
<Grid item xs={4}>
<p className="details">Lorem Ipsum</p>
</Grid>
<Grid item xs={4}>
<img className="edit-icon" src="icon_edit.png"/>
</Grid>
</Grid>
<Grid container>
<Grid item xs={4}>
<p className="details-label">Phone</p>
</Grid>
<Grid item xs={4}>
<p className="details">+123456789</p>
</Grid>
<Grid item xs={4}>
<img className="edit-icon" src="icon_edit.png"/>
</Grid>
</Grid>
</div>
);
};
export default Settings;
Here's one solution:
If you want each container to be editable on click independently, I would separate the code into multiple components:
import React, { useState } from 'react';
import Grid from '#material-ui/core/Grid';
const Container = ({ attr, val }) => {
const [isEditable, setIsEditable] = useState(false)
return (
<Grid container>
<Grid item xs={4}>
<p className="details-label">{attr}</p>
</Grid>
<Grid item xs={4}>
{isEditable ? <input type="text" defaultValue={val} /> : <p className="details">{val}</p>}
</Grid>
<Grid item xs={4}>
<img onClick={() => setIsEditable(!isEditable)} className="edit-icon"
src="icon_edit.png"/>
</Grid>
</Grid>
)
}
const Settings = (props) => {
return (
<div>
<p>Settings</p>
<Container attr="NAME" val="John Doe" />
<Container attr="Phone" val="+123456789"/>
</div>
);
};
export default Settings;
I'd suggest you do this declaratively now that you're using React.
Here's a Codesandbox if you want to play around.
Also note you must set your defaultValue to the same p value, for better UX. It works well for multiple grid containers.
import React from 'react';
import React, { useState } from 'react';
import Grid from '#material-ui/core/Grid';
const Settings = () => {
const [editable, setEditable] = useState(0);
return (
<div>
<Grid container>
<Grid item xs={4}>
<p className="details-label">NAME</p>
</Grid>
<Grid item xs={4}>
{ editable ? <input type="text" defaultValue="Lorem Ipsum"> :
<p className="details">Lorem Ipsum</p> }
</Grid>
<Grid item xs={4}>
<img className="edit-icon" src="icon_edit.png"/>
</Grid>
</Grid>
<Grid container>
<Grid item xs={4}>
<p className="details-label">Phone</p>
</Grid>
<Grid item xs={4}>
{ editable ? <input type="text" defaultValue="+123456789"> :
<p className="details">Lorem Ipsum</p> }
</Grid>
<Grid item xs={4}>
<img className="edit-icon" src="icon_edit.png"/>
</Grid>
</Grid>
</div>
);
};
export default Settings;
Piggybacking off of Pranav Rustagi's answer, it can be edited to keep the content of the paragraph, by passing it as the value attribute of the input element.
var imageCollection = document.querySelectorAll("[className='edit-icon']");
for (var i = 0; i < imageCollection.length; i++) {
imageCollection[i].onclick = function() {
let parent = this.parentElement.previousElementSibling;
let paragraphValue = parent.children[0].innerHTML;
parent.innerHTML = '';
let input = document.createElement("input");
input.type = "text";
input.value = paragraphValue;
parent.appendChild(input);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div>
<Grid container>
<Grid item xs={4}>
<p className="details-label">NAME</p>
</Grid>
<Grid item xs={4}>
<p className="details">Lorem Ipsum</p>
</Grid>
<Grid item xs={4}>
<img className="edit-icon" src="icon_edit.png"/>
</Grid>
</Grid>
<Grid container>
<Grid item xs={4}>
<p className="details-label">Phone</p>
</Grid>
<Grid item xs={4}>
<p className="details">+123456789</p>
</Grid>
<Grid item xs={4}>
<img className="edit-icon" src="icon_edit.png"/>
</Grid>
</Grid>
</div>
I currently have a table using a slider to provide additional details for a table. When the slider component opens I have an X to close to the slider. I am attempting to have that X close the slider and have the table in its original form appear.
Here is a code sandbox:
code sandbox
Slider component :
function ExpandToggle(isOpenProps) {
const [isOpen, setIsOpen] = useState(false);
const toggle = () => {
setIsOpen(!isOpen);
};
return (
<>
<Button>
<ArrowForwardIosIcon size="small" onClick={toggle} />{" "}
</Button>
<SliderInfo open={isOpen} />
</>
);
}
SliderInfo component with onClick={open=false}
export default function SliderInfo({ open }) {
const classes = useStyles();
return (
<Slide direction="left" in={open} mountOnEnter unmountOnExit>
<div className={classes.root}>
<Grid container>
<Grid item>
<Typography variant="h6">Vanila Ice Cream</Typography>
</Grid>
<Grid item>
<Typography variant="h6">Chocolate Ice Cream</Typography>
</Grid>
<Grid item>
<Typography variant="h6">Strawberry Ice Cream</Typography>
</Grid>
<Grid item>
<Typography variant="h6">Sherbert </Typography>
</Grid>
<Grid item>
<Typography variant="h6">None</Typography>
</Grid>
<Grid item>
<Button>
<CloseIcon onClick={open=false} />
</Button>
</Grid>
</Grid>
</div>
</Slide>
On CloseIcon I have an onClick that i'm trying to set open which is passed from Slider to false so it can close the slider component. At the moment upon clicking on the CloseIcon it is not do anything.
Don't modify props directly.
Pass in the toggle function just like you passed in the open variable, and call it instead.
<SliderInfo open={isOpen} toggleOpen={toggle} />
// In Sliderinfo
export default function SliderInfo({ open, toggleOpen }) {
...
<CloseIcon onClick={toggleOpen} />
If your toggle doesn't serve the same purpose, create a new function that only sets isOpen to false and use it instead.
Also remember that onClick expects a function. So the open=false is actually getting executed during render, not after a click. Correct inline format would be onClick={(e) => {//do stuff}}.
You can pass a callback function to the Slider that can call your setIsOpen state modifier, and then pass it to onClick:
function ExpandToggle(isOpenProps) {
const [isOpen, setIsOpen] = useState(false);
const toggle = () => {
setIsOpen(!isOpen);
};
return (
<>
<Button>
<ArrowForwardIosIcon size="small" onClick={toggle} />{" "}
</Button>
<SliderInfo open={isOpen} onRequestClose={() => { setIsOpen(false) }} />
</>
);
}
export default function SliderInfo({ open, onRequestClose }) {
const classes = useStyles();
return (
<Slide direction="left" in={open} mountOnEnter unmountOnExit>
<div className={classes.root}>
<Grid container>
<Grid item>
<Typography variant="h6">Vanila Ice Cream</Typography>
</Grid>
<Grid item>
<Typography variant="h6">Chocolate Ice Cream</Typography>
</Grid>
<Grid item>
<Typography variant="h6">Strawberry Ice Cream</Typography>
</Grid>
<Grid item>
<Typography variant="h6">Sherbert </Typography>
</Grid>
<Grid item>
<Typography variant="h6">None</Typography>
</Grid>
<Grid item>
<Button>
<CloseIcon onClick={onRequestClose} />
</Button>
</Grid>
</Grid>
</div>
</Slide>