Related
The code below I have provided , one example opens the dialog. And the dialog has add functionality which is the addEmail where in you can add multiple fields which is inside the dialog.
I wanna know is that when I close the dialog using the onClick={handleClose} it should reset the dialog, fields that I added should not show after I close since I did not save it.
So when I click cancel it should reset the state.
Thanks for any idea.
for example here I added fields when I close this and open again these field should not show cause it should reset when I close.
#interface.ts
export type EditPropertiesProps = {
open: boolean;
handleClose: () => void;
selectedRow: IRegional
};
#Code snippet - main page --- this calls and opens the dialog
const handleClose = () => {
console.log('here')
setOpen(false);
};
<EditProperties open={open} handleClose={handleClose} selectedRow={selectedRow} />
#EditProperties ts code
export const RegionalListData: IRegionalList[] = [
{
id: 4,
name: "Associate Director of Construction Ops",
column: "associateDirectorofConstructionOps",
emails: [
{
emailAddress: "associateDir#gmail.com",
firstName: "Associate",
lastName: "Director",
id: Math.floor(Math.random() * 999),
fetching: false,
},
],
},
{
id: 5,
name: "CAM Manager",
column: "camManager",
emails: [
{
emailAddress: "associateDir#gmail.com",
firstName: "Associate",
lastName: "Director",
id: Math.floor(Math.random() * 999),
fetching: false,
},
],
},
{
id: 6,
name: "CAO-Chief Administrative Officer",
column: "caoChiefAdministrativeOfficer",
emails: [
{
emailAddress: "associateDir#gmail.com",
firstName: "Associate",
lastName: "Director",
id: Math.floor(Math.random() * 999),
fetching: false,
},
],
},
];
type InitialReqPaylod = {
accountId: number;
regionalRoleUserDto: IRegional;
};
type IData = {
regionName: string;
marketName: string;
subRegionName: string;
};
type IEmail = {
emailAddress: string;
firstName: string;
id: number;
lastName: string;
};
const EditProperties: FC<EditPropertiesProps> = ({
open,
handleClose,
selectedRow,
}) => {
const dispatch = useAppDispatch();
const [isEmailOpen, setOpenEmail] = useState(false);
const [fetching, setFetching] = useState(false);
const [RegionalList, setRegionalList] = useState<IRegionalList[]>(
RegionalListData
);
const [data, setData] = useState<IData>({
regionName: "",
marketName: "",
subRegionName: "",
});
const [regionalId, setRegionalId] = useState<number | null>(null);
const [emailCurrentIndex, setEmailCurrentIndex] = useState<number | null>(
null
);
const [selectedEmailId, setSelectedEmailId] = useState<number | null>(null);
const { isSuccess } = useAppSelector((state) => state.yardUser);
const { isSaveSuccess } = useAppSelector((state) => state.region);
const email = useAppSelector((state) => state.yardUser);
const [emailOptions, setEmailOptions] = useState<IEmail[]>([]);
const emailList = email.data ? email.data.data : [];
useEffect(() => {
if (selectedRow) {
setData({
regionName: selectedRow["regionName"],
marketName: selectedRow["marketName"],
subRegionName: selectedRow["subRegionName"],
});
let regional = [...RegionalList];
for (const k in selectedRow) {
regional.map((prop: IRegionalList) => {
if (prop.column === k) {
prop.emails = selectedRow[k] ? selectedRow[k] : [];
}
});
}
setRegionalList(regional);
}
}, [selectedRow]);
const [maxWidth, setMaxWidth] = React.useState<DialogProps["maxWidth"]>("md");
const fetchEmailResult = React.useMemo(
() =>
throttle(
(event: any, callback: (results: IEmail[]) => void) => {
const payload: IYardUserRequestPayload | InitialReqPaylod = {
accountId: 1,
searchString: event.target.value,
};
fetch(
`https://jsonplaceholder.typicode.com/users?email=${event.target.value}`
)
.then((res) => res.json())
.then((res) => res.data ? callback(res.data.slice(0, 10)) : callback([]))
},
200
),
[]
);
const emailOnChange = (event: any, regionalId: number, index: number, emailId: number) => {
setRegionalId(regionalId);
setEmailCurrentIndex(index);
setSelectedEmailId(emailId);
fetchEmailResult(event,(results: IEmail[]) => {
console.log('results' , results)
if (results.length) setEmailOptions(results);
});
};
useEffect(() => {
if (isSaveSuccess) {
handleClose();
}
}, [isSaveSuccess]);
useEffect(() => {
if (isSuccess) {
setFetching(false);
}
}, [isSuccess]);
const addEmail = (id: number) => {
setRegionalList((list) =>
list.map((item) => {
if (item.id === id) {
return {
...item,
emails: [
...item.emails,
{
emailAddress: "",
firstName: "",
lastName: "",
id: Math.floor(Math.random() * 999),
fetching: false,
},
],
};
}
return item;
})
);
};
const deleteEmail = (email: IEmail, regionId: number) => {
const regionalListCopy = [...RegionalList].map((prop: IRegionalList) => {
if (prop.id === regionId) {
return {
...prop,
emails: prop.emails.filter((prop) => prop.id !== email.id),
};
}
return { ...prop };
});
setRegionalList(regionalListCopy);
};
const setOnChangeOption = (email) => {
setSelectedEmailId(null);
setRegionalList((list) =>
list.map((item) => {
if (item.id === regionalId) {
return {
...item,
emails: [
...item.emails.map((prop) => {
return {
...prop,
...email,
};
}),
],
};
}
return item;
})
);
};
const EmailItem = ({ email, mIndex, prop }) => (
<>
<div style={{ display: "block" }} key={email.id}>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginTop: 15
}}
>
<Autocomplete
options={emailOptions}
getOptionLabel={(option: IEmail) => option.emailAddress}
onInputChange={($event) => emailOnChange($event, prop.id, mIndex, email.id)}
onChange={($event, value) => setOnChangeOption(value)}
fullWidth
open={email.id === selectedEmailId}
renderInput={(params) => (
<TextField size="small" {...params} variant="standard" />
)}
renderOption={(props, option) => {
return (
<Box component="li" {...props}>
{option.emailAddress}
</Box>
);
}}
/>
<DeleteIcon
style={{ color: "red", cursor: "pointer" }}
onClick={() => deleteEmail(email, prop.id)}
/>
</div>
<div
style={{
fontSize: ".8em",
display: "flex",
justifyContent: "space-between",
}}
>
<span style={{ paddingTop: 5 }}>
Email : {email.emailAddress}
Full Name: {email.firstName} {email.lastName}
</span>
{/* <span style={{ paddingRight : 40 }}>{fetching ? "Fetching...." : null}</span> */}
</div>
</div>
</>
);
return (
<Dialog
maxWidth={maxWidth}
open={open}
onClose={handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Edit</DialogTitle>
<DialogContent>
<Card sx={{ minWidth: 275 }} style={{ padding: 20 }}>
<div>
<span>Sub-Region (Sub-Division)</span>
<Divider style={{ marginTop: 10 }} />
<FormControl sx={{ mt: 2, minWidth: 720 }}>
<TextField
label="Region (Division)"
variant="filled"
value={data.regionName}
/>
</FormControl>
</div>
<div style={{ marginTop: 10 }}>
<span>Sub-Region (Sub-Division)</span>
<Divider style={{ marginTop: 10 }} />
<FormControl sx={{ mt: 2, minWidth: 720 }}>
<TextField
label="Sub-Region (Sub-Division)"
variant="filled"
value={data.subRegionName}
/>
</FormControl>
</div>
<div style={{ marginTop: 10 }}>
<span>Market</span>
<Divider style={{ marginTop: 10 }} />
<FormControl sx={{ mt: 2, minWidth: 720 }}>
<TextField
label="Market"
variant="filled"
value={data.marketName}
/>
</FormControl>
</div>
</Card>
{RegionalList.map((prop: IRegionalList, index: number) => (
<Card
sx={{ minWidth: 275 }}
style={{ overflow: "visible", padding: 20, marginTop: 20 }}
key={prop.id}
>
<div style={{ display: "flex", alignItems: "center" }}>
{prop.name}*{" "}
<AddIcon
style={{ marginLeft: 5, cursor: "pointer" }}
onClick={() => addEmail(prop.id)}
/>
</div>
<Divider style={{ marginTop: 10 }} />
{prop.emails.map((email: IEmail, mIndex: number) => (
<EmailItem
key={email.id}
prop={prop}
email={email}
mIndex={mIndex}
/>
))}
</Card>
))}
</DialogContent>
<DialogActions
style={{ marginTop: "20px", marginRight: "20px", marginBottom: "20px" }}
>
<Button onClick={handleClose}>Cancel</Button>
<Button variant="contained" onClick={() => saveChanges()} autoFocus>
Save Changes
</Button>
</DialogActions>
</Dialog>
);
};
export default EditProperties;
You need just reset all used states as values of form when clicking handleClose, my suggestion would be to use just one object state for form values.
Example:
const onClose = () => {
handleClose();
setRegionalList(RegionalListData);
}
return (
<Dialog
maxWidth={maxWidth}
open={open}
onClose={onClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
I'm trying to fetch data using api and show the data in my datagrid. but initially the data is not loading. though I can get the data, and I don't know why it doesn't show in the datagrid. What I'm actually doing is, I have a common function for datagrid along with search option in one file. I'm getting the getting the data in another file. Now everytime I make a change and save the file, it shows the data, but when I refresh the page the data is not showing again. kindly help me figure out. Thanks in advance
this the code where I'm getting the data
const columns = [
{ field: 'role', headerName: 'Role', },
{ field: 'counterParty', headerName: 'Counter Party', },
{ field: 'tokens', headerName: 'Token', },
{ field: 'date', headerName: 'Date', },
{ field: 'comment', headerName: 'Comments', }
];
export default function TransactionCard(props) {
const [TransactionData, setTransactionData] = useState([]);
const [loading, setLoading] = useState(true);
// setLoading(loading, true);
useEffect(() => {
axios.get('http://localhost:8006/api/v2/user/transactions').then(function (res) {
try {
var result = res.data;
// console.log(result.data.data)
setTransactionData(result.data.data)
// setLoading(false);
}
catch (error) {
console.log(error)
}
})
}, [])
console.log(TransactionData)
return (
<>
<Card {...props}>
<CardContent>
<DataGridHelper title='Transaction' rows={TransactionData} columns={columns} />
</CardContent>
</Card>
</>
);
}
This is Where I'm getting the data
const DataGridHelper = ({ rows, columns, title }) => {
const [platform, setPlatform] = useState([]);
const [searchText, setSearchText] = useState('');
const [Rows, setRows] = useState([]);
useEffect(() => {
setPlatform(rows);
setRows(rows);
}, []);
console.log(Rows);
function escapeRegExp(value) {
return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
}
const requestSearch = (searchValue) => {
const searchRegex = new RegExp(escapeRegExp(searchValue), 'i');
const filteredRows = platform.filter((row) => {
return Object.keys(row).some((field) => {
return searchRegex.test(row[field].toString());
});
});
setRows(filteredRows);
};
console.log(rows)
return (
<>
<Stack direction="row" alignItems="center" justifyContent='space-between' gap={1}>
<Stack direction="row" alignItems="center" gap={1}>
<RuleIcon sx={{ color: "text.secondary" }} />
<Typography sx={{ fontSize: 16, fontWeight: 'bold' }} color="text.secondary" gutterBottom>
{title}
</Typography></Stack>
<Box sx={{ flexDirection: 'column' }}>
<TextField
variant="outlined"
size='small'
value={searchText}
onChange={(e) => { setSearchText(e.target.value); requestSearch(e.target.value) }}
placeholder="Search..."
InputProps={{
startAdornment: <SearchIcon fontSize="small" color="action" />,
endAdornment: (
<IconButton
title="Clear"
aria-label="Clear"
size="small"
style={{ visibility: searchText ? 'visible' : 'hidden', borderRadius: "57%", paddingRight: "1px", margin: "0", fontSize: "1.25rem" }}
onClick={(e) => { setSearchText(''); setRows(platform) }}
>
<ClearIcon fontSize="small" color="action" />
</IconButton>
),
}}
sx={{
width: { xs: 1, sm: 'auto' }, m: (theme) => theme.spacing(1, 0.5, 1.5),
'& .MuiSvgIcon-root': {
mr: 0.5,
},
'& .MuiInput-underline:before': {
borderBottom: 1,
borderColor: 'divider',
},
}}
/>
</Box>
</Stack>
<div style={{ height: 250, width: '100%' }}>
<DataGrid
disableColumnMenu
rows={Rows}
columns={columns}
pageSize={10}
rowsPerPageOptions={[10]}
/>
</div>
</>
);
}
export default DataGridHelper
this is the data I'm getting initially
first of all, your code is so dirty :), i cant test your code cause its have your rest API and you don't name consoles, i just understand which one is result of axios, but i think your mistake is on useEffect depandecies in DataGridHelper you must write rows in it, and second maybe in useEffect when you get data in rest API you might write if condition for try in axios tell that if(!!result.data.data) then do that i think it must your problem
useEffect(() => {
setPlatform(rows);
setRows(rows);
}, [rows]);
and :
useEffect(() => {
axios.get('http://localhost:8006/api/v2/user/transactions').then(function (res) {
try {
if(!!res.data){
var result = res.data;
// console.log(result.data.data)
setTransactionData(result.data.data)
// setLoading(false);
}
}
catch (error) {
console.log(error)
}
})
}, [])
I tried to do it with useStyles. I have the following code:
// imports above here
const useStyles = makeStyles((theme) => ({
placeholder: {
color: 'black',
fontSize: 'large',
},
}));
export default function Chatbox() {
const classes = useStyles;
const {currentChannel} = React.useContext(globalContext);
const [placeholder, setPlaceholder] =
React.useState('Message ' + Object.values({currentChannel})[0]);
useEffect(() => {
setPlaceholder('Message ' + Object.values({currentChannel})[0]);
}, [currentChannel]);
return (
<Paper
component="form"
sx={{
p: '4px 8px', display: 'flex', alignItems: 'center',
flexShrink: 1, width: 1670}}>
<InputBase
sx={{ml: 4, flex: 1}}
placeholder={placeholder}
inputProps={{'aria-label': 'chatbox'}}
className= {classes.placeholder}
/>
<Divider sx={{height: 48, m: 0.5}} orientation="vertical" />
<IconButton sx={{p: '25px'}} aria-label="send">
<SendIcon />
</IconButton>
</Paper>
);
}
However, my placeholder size and color never change even after changing the values in useStyles.. It stays grey and the same size.
You forgot to call the function.
// imports above here
const useStyles = makeStyles((theme) => ({
placeholder: {
color: 'black',
fontSize: 'large',
},
}));
export default function Chatbox() {
const classes = useStyles(); // <--------- Here
const {currentChannel} = React.useContext(globalContext);
const [placeholder, setPlaceholder] =
React.useState('Message ' + Object.values({currentChannel})[0]);
useEffect(() => {
setPlaceholder('Message ' + Object.values({currentChannel})[0]);
}, [currentChannel]);
I need to update Parent table when data is changed from child edit form. Not getting the updated data in parent component.
I'm passing the data using all the passible ways as per my understanding. I'm not much experienced in react. So it would be really very helpful if someone can help me to understand where i'm making mistake.
PARENT Component is class component-
import Radium from 'radium';
import Dock from 'react-dock';
import {Divider} from '#material-ui/core';
import "react-tabulator/lib/styles.css";
import "react-tabulator/css/bootstrap/tabulator_bootstrap.min.css";
import { React15Tabulator, reactFormatter, MultiValueFormatter } from "react-tabulator";
import {Badge, Row, Button, Col,Card} from 'react-bootstrap';
import EditServer from '../EditServer';
import Confirm from '../../../ui-components/Confirm';
// import './index.scss';
import jsondata from '../../../constants/data/json/ApplicationServer.json';
const styles = {
root: {
fontSize: '16px',
color: '#999',
height: '100vh',
},
main: {
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
paddingTop: '30vh',
},
dockContent: {
// width: '400px',
height: '100%',
display: 'flex',
alignItems: 'left',
padding:'1rem',
overflowX:"hidden",
// justifyContent: 'center',
flexDirection: 'column',
},
remove: {
position: 'absolute',
zIndex: 1,
right: '10px',
top: '10px',
cursor: 'pointer'
}
}
const positions = ['left', 'top', 'right', 'bottom'];
const dimModes = ['transparent', 'none', 'opaque'];
// const dimStyle = ['all']
function SimpleBage (props: any) {
const rowData = props.cell._cell.row.data;
const cellValue = props.cell._cell.value || 'STANDALONE | DOWN | PRIMARY | BACKUP';
if(cellValue === 'STANDALONE'){
return <h5><Badge pill variant="warning" className="btn-size"
onClick={() => alert(rowData.serverStatus)}>
{cellValue}</Badge></h5>;
}
else if(cellValue === 'DOWN'){
return <h5><Badge pill variant="dark" className="btn-size">
{cellValue}</Badge></h5>;
}
else if(cellValue === 'PRIMARY'){
return <h5><Badge pill variant="success" className="btn-size">
{cellValue}</Badge></h5>;
}
else if(cellValue === 'BACKUP'){
return <h5><Badge pill variant="primary" className="btn-size">
{cellValue}</Badge></h5>;
}
else if(cellValue === 'STANDBY'){
return <h5><Badge pill variant="secondary" className="btn-size">
{cellValue}</Badge></h5>;
}
}
const editableColumns = [
{
title: "#",
field: "index",
width: 80,
dir:"asc",
// headerFilter: "input"
},
{
title: "Server Name",
field: "serverName",
hozAlign: "left",
dir:"asc",
},
{
title: "Server Status",
field: "serverStatus",
// width: 100,
hozAlign: 'left',
//formatter: MultiValueFormatter,
formatter: reactFormatter(<SimpleBage />),
},
{
title: "Server Group",
field: "serverGroup",
hozAlign: "left",
},
]
let data = [...jsondata];
const serverListArray =localStorage.getItem("configuration");
class ApplicationServer extends Component {
constructor(props) {
super(props);
this.state = {
data: data,
rowSelection:"",
stopBtnVisible:false,
startBtnVisble:true,
selectedServerName: "",
selectedServerGroup:"",
selectedServerStatus:"",
selectedServerStatusChange:this.state,
positionIdx: 2,
dimModeIdx: "transparent",
isVisible: false,
fluid: true,
customAnimation: true,
slow: true,
size: 0.30,
isServerStarted:this.state,
serverName:null,
rowIndex:null,
};
this.handleVisibleChange = this.handleVisibleChange.bind(this);
this.handleChange = this.handleChange.bind(this);
this.onClose= this.onClose.bind(this);
}
ref = null;
onClose = isVisible =>{
this.setState({ isVisible: false });
}
clearData = () => {
this.setState({ data: [] });
};
handleChange = (handler) =>{
// console.log("update handler data", serverGroup)
// const updatedServerGroup = event.target.value;
// console.log("handle form submit in table", this.state.selectedServerGroup, this.props.serverGroup);
console.log("handle form submit in table", handler);
this.setState({
...handler
//selectedServerGroup:handler.target.serverGroup
})
//console.log("handle form submit in table", this.state);
console.log("handle form submit in table", handler);
}
render(){
const options = {
height: 215,
movableRows: true,
history: true,
movableColumns: true,
resizableRows: true ,
reactiveData:true,
};
const duration = this.state.slow ? 1000 : 100;
const dur = duration / 1000;
const transitions = ['left', 'top', 'width', 'height']
.map(p => `${p} ${dur}s cubic-bezier(0, 1.5, 0.5, 1)`)
.join(',');
console.log("Render data:", serverListArray);
if(Array.isArray(serverListArray) && serverListArray.length>0){
data=[...serverListArray];
//jsondata= serverListArray;
}
return(
<div style={[styles.root]}>
<div style={{
position: 'relative',
height: 'calc(100vh - 50px)',
}}>
<Row className="table-control-bar">
<Col sm={8}><h5>Server Controls</h5></Col>
<Col sm={4} className="text-right">
<Button variant={this.state.failoverButtonVariant}
className="mr-2"
id="serverFailover"
onClick={this.handleServerFailover}
selectedserverName={this.selectedserverName}
disabled={this.state.failoverButtonDisabled}>Failover</Button>
<Button variant={this.state.editButtonVariant}
className="mr-2"
id="serverEdit"
selectedServerName={this.selectedServerName}
disabled={this.state.editButtonDisabled}
onClick={this.handleVisibleChange}>Edit</Button>
{this.state.stopBtnVisible === false &&
(
<Button
onClick={this.handleServerStart}
className="mr-2"
id="serverStart"
selectedserverName={this.selectedserverName}
visible={this.state.startBtnVisible}
variant={this.state.startButtonVariant}
disabled={this.state.startButtonDisabled}>Start
</Button>
)}
{this.state.startBtnVisible === false &&
(<Button onClick={this.handleServerStop}
className="mr-2"
id="serverStop"
selectedserverName={this.selectedserverName}
variant="primary">Stop</Button>)}
<Button variant={this.state.restartButtonVariant}
id="serverRestart"
onClick={this.handleServerRestart}
selectedserverName={this.selectedserverName}
disabled={this.state.restartButtonDisabled}>Restart</Button>
</Col>
</Row>
<div>
<React15Tabulator
columns={editableColumns}
data={data}
selectable={1}
rowClick={this.rowClick}
options={options}
data-custom-attr="test-custom-attribute"
className={"custom-css-class" + this.state.rowSelection}
tooltips={true}
layout={"fitData"}
/>
</div>
</div>
<div>
<Dock position={positions[this.state.positionIdx]}
size={this.state.size}
dimMode={dimModes[this.state.dimModeIdx]}
isVisible={this.state.isVisible}
onVisibleChange={this.handleVisibleChange}
fluid={this.state.fluid}
dimStyle={{ background: 'rgba(0, 0, 100, 0.2)'}, {pointerEvents:'all !important'}}
dockStyle={this.state.customAnimation ? { transition: transitions } : null, {top:'6%'} }
// ,{top:'13%'}
dockHiddenStyle={this.state.customAnimation ? {
transition: [transitions, `opacity 0.01s linear ${dur}s`].join(',')
} : null}
duration={duration}>
{({ position, isResizing }) =>
<div style={[styles.dockContent]} className="modal-container">
<h4>Edit Server Group</h4>
<Divider />
<EditServer
handleInputChange={this.handleChange}
// handleChange = {e => console.log(e)}
serverName={this.state.selectedServerName}
serverGroup= {this.state.selectedServerGroup}
onClose={this.onClose} />
<span onClick={() => this.setState({ isVisible: false })}
style={styles.remove} title="close">✖</span>
</div>
}
</Dock>
</div>
</div>
)
}
handleSizeChange = size => {
this.setState({ size });
}
}
export default ApplicationServer = Radium(ApplicationServer);
CHILD Component is functional component-
import {func, string} from 'prop-types';
import {makeStyles } from '#material-ui/core';
import {Row, Col, Button, Form} from 'react-bootstrap';
import toast from '../../../ui-components/Toaster';
import Input from '../../../ui-components/Input';
const useStyles = makeStyles((theme) => ({
root: {
'& > *': {
margin: theme.spacing(2),
},
},
formControl: {
margin: theme.spacing(1),
minWidth: 120,
maxWidth: 300,
},
chips: {
display: 'flex',
flexWrap: 'wrap',
},
chip: {
margin: 2,
},
noLabel: {
marginTop: theme.spacing(3),
},
}));
function getStyles(name, personName, theme) {
return {
fontWeight:
personName.indexOf(name) === -1
? theme.typography.fontWeightRegular
: theme.typography.fontWeightMedium,
};
}
export default function EditServer(props) {
const {onClose} = props;
let serverGroup = props.serverGroup;
const initialFormState = {
id: null,
serverName: props.serverName,
serverGroup: props.serverGroup,
saveDisabled: true,
cancelDisabled:true,
showDockModal:false,
edited:false,
}
// console.log("inside child", initialFormState);
const [handler, setHandler] = useState();
//const ref = useRef(null);
const handleInputChange = (event) => {
//event.preventDefault();
console.log("edit server props input change", handler);
let { name, value } = event.target;
//handler.serverGroup = event.target.value;
setHandler({...handler, [name]: value, edited:true});
console.log("inside edit form change:", handler, value, name);
}
const handleFormSubmit = (event) => {
//console.log('inside handleFormSubmit', event, props);
event.preventDefault();
onClose();
if (handler.edited){
//let newServerGroup= handler.serverGroup;
//console.log("form submit", handler);
setHandler({
...handler,
edited:false,
});
console.log("inside edit form change:", handler, event)
// props.serverGroup=newServerGroup;
// return handleInputChange(handler.serverGroup.value);
return toast.success(initialFormState.serverGroup + " Server Group Changed to SIMULATION !");
}
}
return (
<React.Fragment>
<Form className="scrollY"
onSubmit={handleFormSubmit}
>
<Row>
<Col sm={4} className="text-align-right">
<label htmlFor="serverName">Server Name<span className="red">*</span></label>
</Col>
<Col sm={8}>
<Input
type="text"
required
id="severName"
name="severName"
// label="Handler Name"
fullWidth
autoComplete="given-name"
value={initialFormState.serverName}
onChange={handleInputChange}
disabled="true"
/>
</Col>
</Row>
<Row>
<Col sm={4} className="text-align-right">
<label htmlFor="serverGroup" required>Server Group<span className="red">*</span></label>
</Col>
<Col sm={8}>
<Input
type="string"
required
id="serverGroup"
name="serverGroup"
// label="Handler Speed"
fullWidth
autoComplete="family-name"
defaultValue={initialFormState.serverGroup}
onChange={handleInputChange}
/>
</Col>
</Row>
<Row>
<Col sm={4}>
{/* <Button variant="secondary" disabled className="btn-custom" onClick={handleClose}>Cancel</Button>*/}
</Col>
<Col sm={8}>
<Button type="submit"
variant="primary"
className="btn-custom"
>
Submit
</Button>
</Col>
</Row>
</Form>
</React.Fragment>
);
}
EditServer.propTypes = {
onSuccess: func,
};
I'm using react tabulator.
Appreciate the help. Thank you.
In React Native, how do you change the style of a textInput when it gets focus? Say I have something like
class MyInput extends Component {
render () {
return <TextInput style={styles.textInput} />;
}
};
const stylesObj = {
textInput: {
height: 50,
fontSize: 15,
backgroundColor: 'yellow',
color: 'black',
}
};
const styles = StyleSheet.create(stylesObj);
And I want to change the background color on focus to green.
This documentation leads me to believe that the solution is something like
class MyInput extends Component {
constructor (props) {
super(props);
this.state = {hasFocus: false};
}
render () {
return (<TextInput
style={this.state.hasFocus ? styles.focusedTextInput : styles.textInput}
onFocus={this.setFocus.bind(this, true)}
onBlur={this.setFocus.bind(this, false)}
/>);
}
setFocus (hasFocus) {
this.setState({hasFocus});
}
};
const stylesObj = {
textInput: {
height: 50,
fontSize: 15,
backgroundColor: 'yellow',
color: 'black',
}
};
const styles = StyleSheet.create({
...stylesObj,
focusedTextInput: {
...stylesObj,
backgroundColor: 'green',
}
});
Ignoring potential mistakes in the styles structuring, would this be considered correct way to handle it? It seems very verbose to me.
You can achieve this by passing in the onFocus and onBlur events to set and unset styles when focused and blurred:
onFocus() {
this.setState({
backgroundColor: 'green'
})
},
onBlur() {
this.setState({
backgroundColor: '#ededed'
})
},
And then, in the TextInput do this:
<TextInput
onBlur={ () => this.onBlur() }
onFocus={ () => this.onFocus() }
style={{ height:60, backgroundColor: this.state.backgroundColor, color: this.state.color }} />
I've set up a full working project here. I hope this helps!
https://rnplay.org/apps/hYrKmQ
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
TextInput
} = React;
var SampleApp = React.createClass({
getInitialState() {
return {
backgroundColor: '#ededed',
color: 'white'
}
},
onFocus() {
this.setState({
backgroundColor: 'green'
})
},
onBlur() {
this.setState({
backgroundColor: '#ededed'
})
},
render: function() {
return (
<View style={styles.container}>
<TextInput
onBlur={ () => this.onBlur() }
onFocus={ () => this.onFocus() }
style={{ height:60, backgroundColor: this.state.backgroundColor, color: this.state.color }} />
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
marginTop:60
}
});
AppRegistry.registerComponent('SampleApp', () => SampleApp);
The best way to control the style when the element is focused / blurred is to create your own TextInput wrapper
export const MyAppTextInput = (props) => {
return (
<TextInput
{...props}
/>
);
};
Note that {...props} will pass in any property you already set or available for TextInput.
Then extend the above component by adding state to apply styles when focus / blur
export const MyAppTextInput = (props) => {
const [isFocused, setIsFocused] = useState(false);
return (
<TextInput
{...props}
style={[props.style, isFocused && {borderWidth: 5, borderColor: 'blue'}]}
onBlur={() => setIsFocused(false)}
onFocus={() => setIsFocused(true)}
/>
);
};
And remember when you use the component to bind the value like in the example (see value={passwordText}); otherwise the value will disappear on blur as a new render commences after the state change.
<MyAppTextInput
style={styles.input}
value={passwordText}
textContentType="password"
autoCompleteType="off"
secureTextEntry
onChangeText={text => {
setPasswordText(text);
}}
/>
You can of course avoid creating a wrapper but if you have more than one input it will create a mess in your input(s) parent components as you will have to add repeating logic.
Use refs, DirectManipulation and setNativeProps for more performance: https://facebook.github.io/react-native/docs/direct-manipulation.
class MyInput extends Component {
focusedInput = () => {
this.textInput.setNativeProps({
style: { backgroundColor: 'green' }
})
}
blurredInput = () => {
this.textInput.setNativeProps({
style: { backgroundColor: 'yellow' }
})
}
render () {
return <TextInput
ref={c => { this.textInput = c}}
style={styles.textInput}
onFocus={this.focusedInput}
onBlur={this.blurredInput} />
}
}
const stylesObj = {
textInput: {
height: 50,
fontSize: 15,
backgroundColor: 'yellow',
color: 'black',
}
}
const styles = StyleSheet.create(stylesObj)
This updates the TextInput component directly without re-rendering the component hierarchy.
You can create a state to keep track of the input-state and use that state to toggle the style. Here is a simple example
const App = () => {
const [isActive, setActive] = useState(false);
return (
<TextInput style={{ color: isActive ? 'black' : 'grey' }} onFocus={() => setActive(true)} onBlur={() => setActive(false)}/>
);
}
Nader Dabit´s pointed me to do something similar -- using the state for styles -- but I think it can be done in a cleaner way if you created separate styles for the focused and unfocused style and pass only the style ID as follows:
getInitialState() {
return { style: styles.textinput_unfocused }
}
onFocus() {
this.setState({ style: styles.textinput_focused })
}
onBlur() {
this.setState({ style: styles.textinput_unfocused })
}
in render -- referencing by styleID in this.state.style, note how the different styles are passed as an Array:
<TextInput
onBlur={ () => this.onBlur() }
onFocus={ () => this.onFocus() }
style={ [styles.textinput, this.state.style] } />
+ your stylesheet à la carte:
textinput_focused: {
backgroundColor: 'red',
color: 'white'
}
textinput_unfocused: {
backgroundColor: 'green'
}
Hey guys I kinda used everyones idea :p
#Felix gave me an idea that might be perhaps even cleaner. (I would have loved to not have included state though on this static component, just to change styling... But I am to new to this to figure that out.
here was my solution:
import React, { Component } from 'react';
import { StyleSheet, TextInput } from 'react-native';
class TxtInput extends Component {
constructor(props) {
super(props);
this.state = {
style: {},
};
}
onFocus = () => {
const state = { ...this.state };
state.style = {
borderStyle: 'solid',
borderColor: '#e74712',
};
this.setState(state);
}
onBlur = () => {
console.log('on ONBLUR')
const state = { ...this.state };
state.style = {};
this.setState(state);
}
render = () => <TextInput style={[styles.input, this.state.style]} onFocus={() => this.onFocus()} onBlur={() => this.onBlur()} />;
}
const styles = StyleSheet.create({
input: {
color: '#000000',
fontFamily: 'MuseoSans 700 Italic',
fontSize: 22,
borderRadius: 34,
borderStyle: 'solid',
borderColor: 'transparent',
borderWidth: 5,
backgroundColor: '#ffffff',
textAlign: 'center',
width: '25%',
},
});
export default TxtInput;
I added the style into an array, have all the actual input styling done on the first property of the array and the second one the nit picking of the focus and blue.
Hope it helps
For that propose I design this simple logic in functional component (it works the same in class components with the pertinents changes), it can be apply to several <textinputs/>. Below I leave an example:
// state
const [isFocused, setIsFocused] = useState({
name: false,
email: false,
phone: false,
})
// handlers
const handleInputFocus = (textinput) => {
setIsFocused({
[textinput]: true
})
}
const handleInputBlur = (textinput) => {
setIsFocused({
[textinput]: false
})
}
// JSX
<View style={styles.form} >
<TextInput
style={isFocused.name ? [styles.inputs, { borderColor: 'blue' }] : styles.inputs}
placeholder='Name'
placeholderTextColor={darkColors.text}
textContentType='name'
keyboardType='default'
onFocus={() => handleInputFocus('name')}
onBlur={() => handleInputBlur('name')}
/>
<TextInput
style={isFocused.email ? [styles.inputs, { borderColor: 'blue' }] : styles.inputs}
placeholder='Email'
placeholderTextColor={darkColors.text}
textContentType='emailAddress'
keyboardType='email-address'
onFocus={() => handleInputFocus('email')}
onBlur={() => handleInputBlur('email')}
/>
<TextInput
style={isFocused.phone ? [styles.inputs, { borderColor: 'blue' }] : styles.inputs}
placeholder='Phone'
placeholderTextColor={darkColors.text}
keyboardType='phone-pad'
onFocus={() => handleInputFocus('phone')}
onBlur={() => handleInputBlur('phone')}
/>
</View>
<TextInput
style={{ backgroundColor: 'white', height: 40, width: 100, alignItems: 'center'
}}
theme={{ colors: { placeholder: 'white', text: 'white', primary: 'white',
underlineColor: 'transparent', background: '#003489' } }}
/>
set initial value in function component
const [warnColor, setWrnColor] = useState("grey");
set this in text input
style={[styles.brdColor, { borderColor: warnColor }]}
set this in stylesheet
brdColor: {
height: 40,
borderColor: "grey",
borderBottomWidth: 1,
marginTop: heightToDp("2%"),
width: "100%",
}
Change TextInput border color on focus, by using react hooks useState and useCallback.
const [isFocused, setIsFocused] = useState(false);
const handleFocus = useCallback(() => {
setIsFocused(!isFocused);
}, [isFocused]);
let bcOnFocus = {
borderColor: isFocused ? '#000000' : '#cccccc',
};
<ScrollView>
<View>
<TextInput
placeholder="Text Field"
style={bcOnFocus}
onFocus={handleFocus}
/>
</View>
</ScrollView>