Material UI TextField select not showing initial value on form edit - react-native

I have an edit form in a modal that lets you edit user info. Here is the relevant portion:
export const EditUserModal = (Props) => {
const [formValues, setFormValues] = useState(Props.userData);
const [reporterData, setReporterData] = React.useState<any[]>([]);
React.useEffect(() => {
let apiClient = new APIClient();
apiClient.getOwners().then((response) => {
setReporterData(response);
});
}, []);
const handleInputChange = (e) => {
const { name, value } = e.target;
setFormValues({
...formValues,
[name]: value,
});
};
return (
<>
<Modal
open={Props.show}
onClose={() => { Props.toggleModal(false)}}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box
component="form"
autoComplete="off"
>
<Typography id="modal-modal-title" variant="h4" component="h4">
Edit User {Props.userData.name}
</Typography>
<div>
<TextField
required
id="outlined-select-basic"
select
name="reports_to"
label="Reports To"
value={formValues.reports_to}
onChange={handleInputChange}
>
{reporterData.map((option) => (
<MenuItem key={option.owner} value={option.owner}>
{option.owner}
</MenuItem>
))}
</TextField>
</div>
</Box>
</Modal>
</>
)
};
The TextField is supposed to show the initial value of {formValues.reports_to}, but it remains blank (the value is still correct) until you make a new selection. reporterData just returns a list of names(string).
I have tried adding it as a defaultValue, which did not work.

Related

How to update input defaultValue in React child component when props change?

I can pass props to the child component, but the input value doesn't change, when I update props (e.g. I send down "second" instead of "first", I can console.log "second" but the input value remains "first".) What could be the problem?
Code example:
// in parent component
const ParentComp = () => {
const [showEdit, setShowEdit] = useState(false);
const [currentElement, setCurrentElement] = useState('');
const myList = [{ label: 'first'}, {label: 'second'}]
const editElement = (el) => {
setShowEdit(true);
setCurrentElement(el);
}
return (
<div>
{myList.map((el, i) => (
<span key={i} onClick={() => editElement(el)}>
{el.label}
</span>
))}
{showEdit && (
<ChildComponent elData={currentElement} />
)}
</div>
)}
// in child component
const ChildComponent = ({ elData }) => {
const [testInput, setTestInput] = useState(elData.label)
return (
<input
onChange={(e) => setTestInput(e.target?.value)}
defaultValue={elData.label}
/>
)
}
I found a working solution but I'm not quite sure how it works.
// old code
<input
onChange={(e) => setTestInput(e.target?.value)}
defaultValue={elData.label}
/>
// new code
<input
onChange={(e) => setTestInput(e.target?.value)}
value={testInput || ''}
/>
Can anyone explain the difference?

why getting error while uploading image in react

I created a form with name, order, image, status feild in my application. I used material design for form design and used react-material-file-upload for image upload.i got the values and viewed in console.After submitting the form it is not added in my web api,getting error in file.filename not defined in server.
Add.js
import FileUpload from "react-material-file-upload";
import TextField from '#mui/material/TextField';
import Grid from '#mui/material/Grid';
function Addcategory(props){
const [files, setFiles] = useState([]);
const handleSubmit =async (event) =>{
event.preventDefault();
const userid=localStorage.getItem("id");
const fileimg =files[0];
console.log(fileimg);
const userData = {
catname:event.target[0].value,
catorder:event.target[2].value,
image:fileimg,
enable:event.target[4].value,
status:1,
createdBy:userid
}
console.log(userData);
await CategoryDataService.create(userData)
.then(res => {
const data=res.data;
console.log(res);
toast.success("Category Added Successfully");
})
.catch((err) => {
// console.log("err",err.response);
toast.error("please try again!");
});
}
return(
<ThemeProvider theme={theme}>
<div style={{ margin:" 30px 130px 30px"}}>
<Box sx={{ border: '2px solid #15171c', borderRadius: '10px'}} >
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
<Grid item xs={12} style={{textAlign:"center"}}>
<h2 style={{textAlign:"center"}}>Category Add</h2>
<Box
component="form"
sx={{
'& .MuiTextField-root': { m: 1,},
}}
onSubmit={handleSubmit}
noValidate
autoComplete="off"
>
<div className="form-display">
<Grid >
<TextField
required
id="outlined-text"
label="Category Name"
name="catname"
autoFocus/>
<TextField
id="outlined-text"
label="Category Order"
name="catorder"
type="number"
/>
<TextField
id="outlined-select-currency"
select
label="Category Status"
name="enable"
helperText="Please select actegory status"
>
{catStatus.map((option) => (
<MenuItem key={option.value} value={option.value} >
{option.label}
</MenuItem>
))}
</TextField>
<Grid item xs={12} columnSpacing={{xs:1}}>
<Grid item xs={12}>
<FileUpload value={files} onChange={setFiles} />
</Grid>
</Grid>
<Stack direction="row" spacing={2} justifyContent="center"
style={{margin:"15px"}}>
<Button variant="outlined" type="submit">
Submit {props.children}
</Button >
<Button variant="outlined" onClick={back}>
Cancel
</Button>
</Stack>
</Grid>
</div>
</Box>
</Grid>
</Grid>
</Box>
</div>
</ThemeProvider>
);
}
server.js
const multer=require("multer");
const fileStorageEngine = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "./uploads");
},
filename:(req, file, cb) =>{
cb(null, Date.now() + "-" + file.originalname);
}
});
const upload = multer({ storage: fileStorageEngine });
app.post('/addCategory', upload.single("image"), async(req,res)=>{
// let file = req.file;
const data={
category_order:req.body.catorder,
category_name:req.body.catname,
category_icon:req.file.filename,
category_enable_disable:req.body.enable,
status:req.body.status,
created_by:req.body.createdBy,
createdAt:Date.now()
}
await models.category.create(data).then(result=>{
res.status(201).json({
Code: "1",
Message: "Category created successfully",
Data: result
});
})
.catch(error=>{
res.status(500).json({
Code: "0",
Message: "Something went wrong,try again.",
Post: error
});
})
});
this api is working in postman but not working while submit the form

Custom React-Admin Component

I am trying to create a custom component for edit/create in react admin. The problem I am facing is that the new updated value is not being taken, what my component is doing is adding and removing values from ChipArray with the values coming from a dropdown select
render() {
return (
<React.Fragment>
<Paper>
{this.state.scopes.map((item, key) => {
return (
<Chip
key={key}
label={item.description}
onDelete={(e) => this.handleDelete(e, item)}
/>
)
})}
</Paper>
<div>
<button onClick={(e) => this.displayChoices(e)}>
{this.state.show ? <span>Hide Scopes Select List</span> : <span>Show Scopes Select List</span>}
</button>
<div/>
{this.state.show ? <Field name="scope" component="Select" placeholder="Spaces"
onChange={(e) => this.handleAdd(e)}>
{this.state.data.map((option, index) =>
<option key={index} value={JSON.stringify(option)}>
{option.description}
</option>
)}
</Field> : ''}
</div>
</React.Fragment>
)
}
}
I manged to remove and add to the ChipArray but when I save the channges were never taken, here is the delete and add functions :
handleAdd = (e) => {
e.preventDefault();
const value = JSON.parse(e.target.value);
let selectedScopes = this.state.scopes;
if (selectedScopes.filter(s => (s.id === value.id)).length === 0) {
selectedScopes.push(value);
this.setState({scopes: [...selectedScopes]});
}
};
handleDelete = (e, value) => {
e.preventDefault();
const selectedScopes = this.state.scopes;
this.setState((prevState, props) => {
return {scopes: prevState.scopes.filter(scope => scope !== value)};
})
};
I know I am supposed to use <Field/> from "react-final-form" but I am not sure how or where.
Really sorry if this question was asked before but I looked online and wasn't so lucky and I am stuck on this.
Thanks

Cannot get react-admin permission checks to work in List Actions

Wanting to show a custom button at the top of the page only if the user is an admin. This works for showing/hiding certain fields on the same page. But for some reason I cannot get it to work within List Actions.
Code:
const UserListActions = ({ permissions, ...props }) => (
<CardActions> .
<RefreshButton />
{permissions === 'admin' &&
<Button color="primary"> .
<SyncIcon /> Sync Users .
</Button> .
} .
</CardActions> .
);
export const UserList = ({ permissions, ...props }) => (
<List actions={<UserListActions />} title="All users" {...props} bulkActions={false}>
Figured this out. I was missing a key piece in passing permissions into the actions property of the List
const RoleListActions = ({ basePath, permissions }) => (
<CardActions>
{permissions === 'admin' && <SyncAwsRolesButton color="primary" />}
{permissions === 'admin' && <CreateButton basePath={basePath} />}
<RefreshButton />
</CardActions>
);
export const RoleList = ({ permissions, ...props }) => (
<List title="All roles" actions={<RoleListActions permissions={permissions} />} {...props} bulkActions={false}>
^^ This bit right here

Editing a Material UI row within React + Redux

I have a material UI table in a react project, and I want a user to click on the pencil/Edit Icon to edit the table row.
This is a loaded question, but would this require an additional piece of Material UI? what would the logic look like to make this happen?? I have most of the code set up on the backend, but don't know how to write this code in the component???
Thanks for looking!
//STYLE VARIABLE BOR MATERIAL BUTTON
const style = {
margin: 12
//
};
const mapStateToProps = (state) => ({
user: state.user,
reduxState: state.getExpense
});
class ExpenseTable extends Component {
constructor(props) {
super(props);
this.state = {
getExpense: []
};
}
isSelected = (index) => {
return this.state.selected.indexOf(index) !== -1;
};
handleRowSelection = (selectedRows) => {
this.setState({
selected: selectedRows,
});
};
//on page load, DISPATCH GET_EXPENSE is
//SENT TO expenseSaga which then
//goes to getExpenseReducer and appends EXPENSE_DATA to the
//DOM
componentDidMount() {
const { id } = this.props.match.params;
this.props.dispatch({ type: USER_ACTIONS.FETCH_USER });
this.props.dispatch({ type: 'GET_EXPENSE' });
}
componentDidUpdate() {
if (!this.props.user.isLoading && this.props.user.userName ===
null) {
this.props.history.push('home');
}
}
logout = () => {
this.props.dispatch(triggerLogout());
// this.props.history.push('home');
};
//SETS STATE FOR ALL INPUTS
handleChange = (name) => {
return (event) => {
this.setState({
[name]: event.target.value
});
};
};
//SUBMIT BUTTON- TRIGGERS DISPATCH TO EXPENSE SAGA TO ADD DATA
handleClick = () => {
console.log('add expense', this.state);
this.props.dispatch({
type: 'ADD_EXPENSE',
payload: this.state
});
};
//TRASH ICON-TRIGGERS DISPATCH TO EXPENSE SAGA DELETE
handleClickRemove = (id) => {
console.log('delete expense', this.state);
this.props.dispatch({
type: 'DELETE_EXPENSE',
payload: id
});
};
handleClickEdit = (row) => {
console.log('edit expense', this.state)
this.props.dispatch({
type: 'EDIT_EXPENSE',
payload: row
})
}
render() {
console.log('HEY-oooo expense render', this.state);
let content = null;
if (this.props.user.userName) {
//MAP OVER REDUX STATE.
const tableRows = this.props.reduxState.map((row) => {
//.MAP SEPARATES DATA INTO INDIVIDUAL ITEMS.
const { id, item_description, purchase_date,
item_price, item_link } = row;
return (
<TableRow selectable={false}>
{/* TABLE ROWS */}
<TableRowColumn>{item_description}
</TableRowColumn>
<TableRowColumn>{purchase_date}
</TableRowColumn>
<TableRowColumn>${item_price}</TableRowColumn>
<TableRowColumn><a href={item_link}>{item_link}
</a></TableRowColumn>
<TableRowColumn><EditIcon class="grow:hover"
onClick={() => {this.handleClickEdit(row)}} />
</TableRowColumn>
<TableRowColumn><TrashIcon onClick={() =>
{this.handleClickRemove(id);
}}/>
</TableRowColumn>
</TableRow>
// END TABLE ROWS
);
});
<div>
{/* FORM FOR ADDING EXPENSES(DATA) */}
<form id="expenseForm">
<h3>
Add a new <br />
expense
</h3>
<input
type="text"
id="fname"
name="fname"
placeholder="Item description"
onChange=
{this.handleChange('item_description')}
/>
<br />
<br />
<input
type="text"
id="lname"
name="lname"
placeholder="Item price"
onChange={this.handleChange('item_price')}
/>
<br />
<input
type="text"
id="lname"
name="lname"
placeholder="Item link"
onChange={this.handleChange('item_link')}
/>
<br />
{/* END FORM */}
<RaisedButton
id="expSubmit"
label="Submit Expense"
primary={true}
style={style}
onClick={this.handleClick}
/>
{/* TABLE TOTAL KEEPS CURRENT TOTAL OF PRICE COLOUMN */}
<h1>Total:</h1>
<br />
<h3>$748.93</h3>
</form>
{/* TABLE HEADERS */}
<Table>
<TableHeader>
<TableRow>
<TableHeaderColumn>Item
description</TableHeaderColumn>
<TableHeaderColumn>Purchase
Date</TableHeaderColumn>
<TableHeaderColumn>Item
Price</TableHeaderColumn>
<TableHeaderColumn>Item
Link</TableHeaderColumn>
<TableHeaderColumn>Edit
entry</TableHeaderColumn>
<TableHeaderColumn>Delete
entry</TableHeaderColumn>
</TableRow>
</TableHeader>
<TableBody>
{tableRows}
</TableBody>
</Table>
</div>
);
}
return (
<div>
<Nav />
{content}
</div>
);
}
}
// this allows us to use <App /> in index.js
export default connect(mapStateToProps)(ExpenseTable);
The default material-ui table doesn't have the feature of in-line editing. You will have to write your own wrapper to achieve this which can be time consuming. To overcome the time issue we can use some good existing libraries.
Here's one powerful library from DevExtreme for the same which i used, but go through their licensing before you take the final decision to use.
https://devexpress.github.io/devextreme-reactive/react/grid/demos/featured/controlled-mode/