I have a component that successfully uses redux-form onSubmit to call an action creator. The creator performs an ajax call but the the action is never dispatched to save it to the store. I must have something messed up in the wiring of react-redux and redux-form, possibly in the binding of the action creator. I have read everything that I have found on Google and still can't find the problem. Any ideas? ( I have included redux-promise to handle the request promise, but it never makes it that far )
import React from 'react';
import { Field, reduxForm } from 'redux-form';
import validate from '../utils/add_person_validation';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { addPersonResponseAction } from '../actions/index';
import renderField from '../components/render_input_field';
// call the action creator - this part succeeds
const doSubmit = function(values) {
addPersonResponseAction(values);
};
let AddPersonContainer = (props) => {
const {
handleSubmit,
pristine,
reset,
submitting
} = props;
return (
<div className="row">
<form onSubmit={handleSubmit(doSubmit)} >
<div className="col-sm-6">
<fieldset>
<legend>Person Info</legend>
<div className="form-group">
<Field name="personFirstName" component={renderField} type="text" label="First Name" className="form-control" />
<Field name="personLastName" component={renderField} type="text" label="Last Name" className="form-control" />
<Field name="birthday" component={renderField} type="date" label="Birthday" className="form-control" />
<Field name="group" component={renderField} type="text" label="Group" className="form-control" />
</div>
</fieldset>
</div>
<div className="form-buttons-container">
<button className="btn btn-default form-button" type="submit" disabled={pristine || submitting}>Submit</button>
<button className="btn btn-default form-button" type="button" disabled={pristine || submitting} onClick={reset}>Clear Values</button>
</div>
</form>
</div>
);
};
const mapStateToProps = function({ addPersonResponse }) {
return { addPersonResponse };
};
const mapDispatchToProps = function(dispatch) {
return bindActionCreators( {addPersonResponseAction}, dispatch);
};
const form = reduxForm({ form: 'addPerson', validate: validate });
AddPersonContainer = connect(mapStateToProps, mapDispatchToProps)(form(AddPersonContainer));
export default AddPersonContainer;
/********************************************
* Action creator
**********************************************/
import axios from 'axios';
export const ADD_PERSON_RESPONSE = 'ADD_PERSON_RESPONSE';
export const addPersonResponseAction = (data) => {
const postURL = 'http://some-url/addperson';
const request = axios.post(postURL, { data });
return {
type: ADD_PERSON_RESPONSE,
payload: request
};
};
Redux wraps actions using mapDispatchToProps - but you are calling the unwrapped version by using the imported method.
// call the action creator - this part succeeds
const doSubmit = function(values) {
addPersonResponseAction(values); <------ Redux does not know anything about this
};
Try:
let AddPersonContainer = (props) => {
const {
handleSubmit,
pristine,
reset,
submitting
} = props;
const doSubmit = function(values) {
props.addPersonResponseAction(values); <----- Try this
}
return (
<div className="row">
<form onSubmit={handleSubmit(doSubmit)} >
<div className="col-sm-6">
<fieldset>
<legend>Person Info</legend>
<div className="form-group">
<Field name="personFirstName" component={renderField} type="text" label="First Name" className="form-control" />
<Field name="personLastName" component={renderField} type="text" label="Last Name" className="form-control" />
<Field name="birthday" component={renderField} type="date" label="Birthday" className="form-control" />
<Field name="group" component={renderField} type="text" label="Group" className="form-control" />
</div>
</fieldset>
</div>
<div className="form-buttons-container">
<button className="btn btn-default form-button" type="submit" disabled={pristine || submitting}>Submit</button>
<button className="btn btn-default form-button" type="button" disabled={pristine || submitting} onClick={reset}>Clear Values</button>
</div>
</form>
</div>
);
};
Because the function you are defining does not have access to props this gives a bit of a twist, so try refactoring it into the component definition.
This is a source of confusion because it is required to import the function so mapDispatchToProps can wrap it...but there is temptation to forget that the real action is in props, not the function itself. So I'm sure you are seeing results in the actual action function, but redux does not know because it is not wrapped in dispatch.
Related
So basically I have a form which i have tried to style somewhat like material Ui.But I would Like to add some date and time pickers.But im getting this error
Module not found: Can't resolve '#mui/x-date-pickers/AdapterDayjs' in '/Users/arundhati/Development/code/Mod5/capstone/client/src/components'
Also there is like lot of weird stuff given in the MUI document .And im confused how i can implement date and time picker here is my code.Thanks :)
function EditReservationForm({ reservation, onUpdateReservation }) {
const { name, date, time, num, contact, occasion } = reservation;
const [updateName, setUpdatedName] = useState(name);
const [updateDate, setUpdatedDate] = useState(date);
const [updateTime, setUpdatedTime] = useState(time);
const [updateNum, setUpdatedNum] = useState(num);
const [updateContact, setUpdatedContact] = useState(contact);
const [updateOccasion, setUpdatedOccasion] = useState(occasion);
function handleEditClick(e) {
e.preventDefault();
fetch(`/reservations/${reservation.id}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: updateName,
date: updateDate,
time: updateTime,
num: updateNum,
contact: updateContact,
occasion: updateOccasion,
}),
})
.then((r) => r.json())
.then((updatedReservation) => {
onUpdateReservation(updatedReservation);
});
}
return (
<>
<Box
component="form"
sx={{
"& > :not(style)": { m: 1 },
}}
noValidate
autoComplete="off"
onSubmit={handleEditClick}
>
<h2>Modify Reservation</h2>
{/* <form onSubmit={handleEditClick} > */}
<FormControl>
<InputLabel htmlFor="component-outlined">Name</InputLabel>
<OutlinedInput
type="text"
// id="email"
id="email"
value={updateName}
onChange={(e) => setUpdatedName(e.target.value)}
label="Name"
/>
</FormControl>
<br />
<FormControl>
<InputLabel htmlFor="component-outlined">Date</InputLabel>
<OutlinedInput
type="date"
// id="email"
id="date"
value={updateDate}
onChange={(e) => setUpdatedDate(e.target.value)}
label="Date"
/>
</FormControl>
<br />
<FormControl>
<InputLabel htmlFor="component-outlined">Time</InputLabel>
<OutlinedInput
type="time"
name="time"
id="time"
value={updateTime}
onChange={(e) => setUpdatedTime(e.target.value)}
/>
</FormControl>
<br />
<FormControl>
<InputLabel htmlFor="component-outlined">No. of Guests</InputLabel>
<OutlinedInput
type="number"
name="num"
value={updateNum}
onChange={(e) => setUpdatedNum(e.target.value)}
/>
</FormControl>
<br />
<FormControl>
<InputLabel htmlFor="component-outlined">Contact</InputLabel>
<OutlinedInput
type="tel"
name="contact"
value={updateContact}
onChange={(e) => setUpdatedContact(e.target.value)}
placeholder="contact"
/>
</FormControl>
<br />
<FormControl>
<InputLabel htmlFor="component-outlined">Occasion</InputLabel>
<OutlinedInput
type="text"
name="occasion"
value={updateOccasion}
onChange={(e) => setUpdatedOccasion(e.target.value)}
/>
</FormControl>
<Stack paddingLeft={15} direction="row" id="loginbutton">
<ColorButton variant="contained" type="submit">
{" "}
Update Reservation
</ColorButton>
</Stack>
{/* </form> */}
</Box>
</>
);
}
export default EditReservationForm;
I have a React frontendand I have styled it using Material UI design.I added the Date and Time component styling to my form and now the form is not able to take up the "name" value and further process with the posting.The prob is only happening in the Date and time input feilds here is the error "TypeError: Cannot read properties of undefined (reading 'name')"....
Pls check out my code thanks.
function ReservationForm(){
const navigate = useNavigate();
const params = useParams();
const {user}=useContext(Cont)
const[reservationData,setReservationData]=useState({
name:"",
date:"",
time:"",
num:"",
contact:"",
occasion:"",
});
function handleReservationChange(event){
setReservationData({
...reservationData,
[event.target.name]: event.target.value,
})
}
function handleReservationSubmit(event){
event.preventDefault();
const newReservation={
...reservationData,
restaurant_id: params.id,
user_id: user.id,
};
fetch(`/reservations`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(newReservation),
})
.then((r) => r.json())
.then(
setReservationData({
name:"",
date:"",
time:"",
num:"",
contact:"",
occasion:"",
})
);
navigate("/myreservations");
}
return(
<>
<Box
component="form"
sx={{
"& > :not(style)": { m: 1 },
}}
noValidate
autoComplete="off"
onSubmit={handleReservationSubmit}
>
<h1 className="editheadings">Reserve 🍽️</h1>
<FormControl className="inputstyle">
<InputLabel htmlFor="component-outlined">Name</InputLabel>
<OutlinedInput
type="text"
name="name"
id="name"
value={reservationData.name}
onChange={handleReservationChange}
label="Name"
/>
</FormControl>
<br />
<FormControl>
<LocalizationProvider name="date" dateAdapter={AdapterDayjs} fullWidth>
<DatePicker
name="date"
label="Date"
value={reservationData.date}
onChange={handleReservationChange}
renderInput={(params) => <TextField {...params} />}
/>
</LocalizationProvider>
</FormControl>
<FormControl>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<TimePicker
name="time" label="Time"
value={reservationData.time} onChange={handleReservationChange}
renderInput={(params) => <TextField {...params} />}
/>
</LocalizationProvider>
</FormControl>
<br />
<FormControl className="inputstyle">
<InputLabel htmlFor="component-outlined">No. of Guests</InputLabel>
<OutlinedInput
type="number"
name="num"
value={reservationData.num} onChange={handleReservationChange}
/>
</FormControl>
<br />
<FormControl className="inputstyle">
<InputLabel htmlFor="component-outlined">Contact</InputLabel>
<OutlinedInput
type="tel"
name="contact"
value={reservationData.contact} onChange={handleReservationChange}
placeholder="contact"
/>
</FormControl>
<br />
<FormControl className="inputstyle">
<InputLabel htmlFor="component-outlined">Occasion</InputLabel>
<OutlinedInput
type="text"
name="occasion"
value={reservationData.occasion} onChange={handleReservationChange}
/>
</FormControl>
<Stack paddingLeft={15} direction="row" id="loginbutton">
<ColorButton variant="contained" type="submit">
{" "}
Update Reservation
</ColorButton>
</Stack>
</Box>
</>
)
}
export default ReservationForm;
Since DatePicker and TimePicker onChange events send the new value instead of event, you need to add new handleChange function for DatePicker and TimePicker components like:
function handleReservationChangeWithNameAndValue(name, newValue) {
setReservationData({
...reservationData,
[name]: newValue
});
}
and pass it in DatePicker and TimePicker components accordingly:
<DatePicker
name="date"
label="Date"
value={reservationData.date}
onChange={(newVal) =>
handleReservationChangeWithNameAndValue("date", newVal)
}
renderInput={(params) => <TextField {...params} />}
/>
<TimePicker
name="time"
label="Time"
value={reservationData.time}
onChange={(newVal) =>
handleReservationChangeWithNameAndValue("time", newVal)
}
renderInput={(params) => <TextField {...params} />}
/>
You can take a look at this sandbox for a live working example of your form with this function.
Better to check this function.
function handleReservationChange(event){
setReservationData({
...reservationData,
[event.target.name]: event.target.value,
})
}
Based on this function, every field should have name property. But as you can see some of them have not that property.
I have a form which needs its css Display to be set to block when I click on a certain button. When I click on the Add button id="add" it should set the css style block for id="modalContent" div.
I've just started react and am completely new to it. I read something about ref but couldn't completely understand how to go through with it.
AddFormMod.tsx
import React from 'react';
import './App.css';
function AddForm(){
return (
<div id="modalContent" className="modal-content">
<h1 id="headerAdd">ADD NEW CONTACT</h1>
<form action="#" id="myForm">
<label className="required label" ><b>Name: </b></label><br />
<input className="form-fields type1" type="text" id="name" name="name" required></input><br/><br/>
<label className="required label" ><b>Email:</b> </label><br/>
<input className="form-fields type1 " type="email" id="email" name="mail" required></input><br/><br/>
<label className="required label" ><b>Mobile:</b> </label>
<label className="label" id="landlinelabel" ><b>Landline:</b></label><br/>
<input className="form-fields" type="tel" id="mobile" name="mobile" pattern="^\d{10}$" required></input>
<input className="form-fields" type="tel" id="landline" name="landline" ></input><br/><br/>
<label className="label" ><b>Website</b></label><br/>
<input className="form-fields type1" type="text" id="website" name="website" ></input><br/><br/>
<label className="label"><b>Address:</b> </label><br/>
<textarea className="addressstyle form-fields" id="address1" name="address1" rows={9} cols={74}></textarea>
<input className = "buttonstyle" type="submit" value="Add" id="adddetails" ></input>
<input className = "buttonstyle" type="button" value="Cancel" id="candetails"></input>
</form>
</div>
);
}
export default AddForm;
App.tsx
import React from 'react';
import './App.css';
import AddForm from './AddFormMod';
function App() {
return (
<p id="title"> Address Book </p>
);
}
function AddHome(){
return (
<div>
<button id="home" >HOME</button>
<button id="add" onClick={} >+ADD</button>
</div>
);
}
function ContactBar(){
return (
<div>
<p id="contacts">CONTACTS</p>
</div>
);
}
export { App , AddHome, ContactBar };
One approach to achieve the result you want, is to utilize conditional rendering. For example, when you click the "add"-button in your AddHome component, you can set a state variable to render the AddForm-component:
function AddHome(){
const [shouldRenderForm, setShouldRenderForm] = useState(false);
return (
<div>
<button id="home" >HOME</button>
<button id="add" onClick={() => setShouldRenderForm(true)} >+ADD</button>
{shouldRenderForm && <AddForm />}
</div>
);
}
I'm also guessing you want to "close the form" after submit or via a close button inside the AddForm-component. To achieve this, simply pass a prop to the component, for the AddForm-component to call to close the form:
// ... in the add AddHome component:
{shouldRenderForm && <AddForm closeForm={() => setShouldRenderForm(false)} />}
// ... in AddForm component:
type AddFormProps = { closeForm: () => void };
function AddForm({ closeForm }: AddFormProps) {
// ... i.e. on a button to close the form
<button type="button" onClick={() => closeForm()}>Cancel</button>
}
Checkout a working example in this sandbox.
I have a strange problem with my form. I can add and remove fields with two several buttons, but the remove button has stopped working. I can see that on clicking still the action "##redux-form/ARRAY_REMOVE" gets fired, but the field does not disappear. I don't really know why it stopped working, I tried to undo all the code I wrote afterwards, but wasn't able to track the error down. Would appreciate any input. Here is my code:
import React from 'react';
import TextField from 'material-ui/TextField';
import { Field, FieldArray, reduxForm} from 'redux-form';
import validate from './validate';
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin(); //Needed, otherwise an error message is shown in the console
const renderTextField = ({input, label, meta: {touched, error}, ...custom}) => (
<TextField
hintText={label}
floatingLabelText={label}
errorText={touched && error}
{...input}
{...custom}
/>
);
const renderUsers = ({fields, meta: { touched, error }}) => (
<div>
<div>
<button className="btn btn-primary"
type="button" onClick={() => fields.push({})}>
<span className="glyphicon glyphicon-plus-sign"/> Add User
</button>
{touched && error && <span>{error}</span>}
</div>
{fields.map((index) =>
<div key={index}>
<Field name={`${index}.firstName`} component={renderTextField} label="First Name"/>
<Field name={`${index}.lastName`} component={renderTextField} label="Last Name"/>
<Field name={`${index}.position`} component={renderTextField} label="Position"/>
<Field name={`${index}.email`} component={renderTextField} label="Email"/>
<button className="btn btn-xs btn-danger"
type="button"
title="Remove User"
onClick={() => fields.remove(index)}>
<span className="glyphicon glyphicon-minus-sign"/>
</button>
</div>
)}
</div>
);
const UserCreation = (props) => {
const { handleSubmit, pristine, reset, submitting} = props;
return (
<form onSubmit={handleSubmit}>
<FieldArray name="users" component={renderUsers}/>
<div>
<button className="btn btn-primary btn-success"
type="submit"
disabled={pristine || submitting}>
<span className="glyphicon glyphicon-send" />
Submit
</button>
{' '}
<button type="button"
className="btn btn-primary btn-danger"
disabled={ pristine || submitting}
onClick={reset}>
Cancel
</button>
</div>
</form>
);
}
export default reduxForm({
form: 'UserCreationForm',
validate
})(UserCreation);
Here is a snapshot from my console when I try to remove the field:
console.log of action
I fixed it. I added a second key to the map function:
{fields.map((user, index) =>
<div key={index}>
<Field name={`${user}.firstName`} component={renderTextField} label="First Name"/>
<Field name={`${user}.lastName`} component={renderTextField} label="Last Name"/>
<Field name={`${user}.position`} component={renderTextField} label="Position"/>
<Field name={`${user}.email`} component={renderTextField} label="Email"/>
Simple question here: In Meteor with React how do I pass a parameter to .jsx . I want to send the :token param to my jsx so I can use it after the form submit.
I'm using kadira's flow-router and react-layout packages
Route
FlowRouter.route('/reset/:token',{
name: 'reset',
action: function(params){
ReactLayout.render(App, {
content: <Reset token={params.token} />
})
}
})
Reset.jsx
Reset = React.createClass({
resetPass(e){
e.preventDefault();
alert("test");
},
render() {
return (
<form onSubmit={this.resetPass}>
<input type="password" id="password"/>
<input type="password" id="confirmation"/><br /><br />
<input type="submit" id="reset-button" value="Reset password" />
</form>
);
}
})
Solved
I can get the info with this.props.token
Reset = React.createClass({
resetPass(e){
e.preventDefault();
alert(this.props.token);
},
render() {
return (
<form onSubmit={this.resetPass}>
<input type="password" id="password"/>
<input type="password" id="confirmation"/><br /><br />
<input type="submit" id="reset-button" value="Reset password" />
</form>
);
}
})