'handleSubmit' is not defined no-undef - react-redux

Here I am getting an error of handleSubmit function because ,here I am using this syntax 'function PostForm () ' instead of 'class PostForm extends Component {}',so what needs to be changed in order to work with handlesubmit function.
function PostForm () {
handleSubmit = (e) => {
e.preventDefault();
const title = this.getTitle.value;
const message = this.getMessage.value;
const data = {
id: new Date(),
title,
message
}
console.log(data)
}
return (
<div>
<h1>Create Post</h1>
<form onSubmit={this.handleSubmit}>
<input required type="text" ref={(input)=>this.getTitle = input}
placeholder="Enter Post Title"/>
<br /><br />
<textarea required rows="5" ref={(input)=>this.getMessage = input} cols="28"
placeholder="Enter Post" />
<br /><br />
<button>Post</button>
</form>
</div>
);
}
export default PostForm;

Since it's the function component you need to define handleSubmit as a function.
For example
const handleSubmit = (e) => {
...
}

Related

Retriving data for input radio won't make a default selection

Goal:
Retrieve data 'smartphones', by API, and apply it as a default selection in the input radio component for the react hook form.
Problem:
The code do not work that makes smartphones as a preselection in the input radio button.
However, if I make a change by using hard coding, it works but hard coding do not solve the case.
I don't know how to solve it.
Info:
*Using React TS and React hook form.
*Newbie in react TS and hook form.
Stackblitz:
https://stackblitz.com/edit/react-ts-z9cnzl
Thank you!
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import './style.css';
type FormValues = {
lastName: string;
favShow: string;
};
export default function App() {
const [category, setCategory] = useState('');
React.useEffect(() => {
async function FetchData() {
var data = await fetch('https://dummyjson.com/products/1').then((res) => {
return res.json();
});
console.log(data.category);
setCategory(data.category);
}
FetchData();
}, []);
const [data, setData] = useState(null);
const { register, handleSubmit } = useForm<FormValues>({
defaultValues: {
lastName: 'asaaaaaaf',
favShow: category,
//favShow: 'smartphones',
},
});
const onSubmit = (data) => {
setData(data);
console.log('asdf');
};
return (
<React.Fragment>
<form onSubmit={handleSubmit(onSubmit)} className="form-container">
<h1 className="form-heading">React Hook Form Example</h1>
<input
{...register('lastName', { required: true })}
className="form-control"
type="text"
placeholder="Last name"
maxLength={15}
name="lastName"
/>
<br />
<br />
<label htmlFor="ted-lasso">
<input
{...register('favShow', { required: true })}
type="radio"
name="favShow"
value="smartphones"
id="smartphones"
/>{' '}
smartphones
</label>
<label htmlFor="got">
<input
{...register('favShow', { required: true })}
type="radio"
name="favShow"
value="GOT"
id="got"
/>
GOT
</label>
<br />
<br />
<button className="submit-btn" type="submit">
Submit
</button>
</form>
{data && <p className="submit-result">{JSON.stringify(data)}</p>}
</React.Fragment>
);
}
I got some help and the solution is:
Stackblitz:
https://stackblitz.com/edit/react-ts-m2s6ev?file=index.tsx
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import './style.css';
type FormValues = {
lastName: string;
favShow: string;
};
export default function App() {
const [category2, setCategory2] = useState();
const [data, setData] = useState(null);
const { register, handleSubmit, resetField } = useForm<FormValues>({
defaultValues: {
lastName: '',
favShow: '',
},
});
React.useEffect(() => {
async function FetchData() {
var data = await fetch('https://dummyjson.com/products/1').then((res) => {
return res.json();
});
setCategory2(data);
}
FetchData();
}, []);
React.useEffect(() => {
if (category2) {
const obj = JSON.parse(JSON.stringify(category2));
console.log(obj);
resetField('lastName', { defaultValue: obj.discountPercentage });
resetField('favShow', { defaultValue: obj.category });
}
}, [resetField, category2]);
const onSubmit = (data) => {
setData(data);
};
return (
<React.Fragment>
<form onSubmit={handleSubmit(onSubmit)} className="form-container">
<h1 className="form-heading">React Hook Form Example</h1>
<input
{...register('lastName', { required: true })}
className="form-control"
type="text"
placeholder="Last name"
maxLength={15}
name="lastName"
/>
<br />
<br />
<label htmlFor="ted-lasso">
<input
{...register('favShow', { required: true })}
type="radio"
name="favShow"
value="smartphones"
id="smartphones"
/>{' '}
smartphones
</label>
<label htmlFor="got">
<input
{...register('favShow', { required: true })}
type="radio"
name="favShow"
value="GOT"
id="got"
/>
GOT
</label>
<br />
<br />
<button className="submit-btn" type="submit">
Submit
</button>
</form>
{data && <p className="submit-result">{JSON.stringify(data)}</p>}
</React.Fragment>
);
}

Google Places API Autocomplete, how to add a second address

I need to search two addresses on the same webpage, one for location, one for correspondence. The first Google API Address works fine, I then tried duplicating the function and form modifying it, but it doesn't populate the second address, it always tries to populate the first address, can anyone tell me where I am going wrong please? Thanks for your help.
function initMap() {
const componentForm = [
'street_number',
'route',
'location',
'locality',
'administrative_area_level_2',
'postal_code',
];
const autocompleteInput = document.getElementById('location');
const options = {
types: ['(cities)'],
componentRestrictions: { country: 'gb' }
};
const autocomplete = new google.maps.places.Autocomplete(autocompleteInput);
autocomplete.addListener('place_changed', function () {
const place = autocomplete.getPlace();
if (!place.geometry) {
// User entered the name of a Place that was not suggested and
// pressed the Enter key, or the Place Details request failed.
window.alert('No details available for input: \'' + place.name + '\'');
return;
}
fillInAddress(place);
});
function fillInAddress(place) { // optional parameter
const addressNameFormat = {
'street_number': 'short_name',
'route': 'long_name',
'locality': 'long_name',
'administrative_area_level_2': 'short_name',
'postal_code': 'short_name',
};
const getAddressComp = function (type) {
for (const component of place.address_components) {
if (component.types[0] === type) {
return component[addressNameFormat[type]];
}
}
return '';
};
document.getElementById('location').value = getAddressComp('street_number') + ' '
+ getAddressComp('route');
for (const component of componentForm) {
// Location field is handled separately above as it has different logic.
if (component !== 'location') {
document.getElementById(component).value = getAddressComp(component);
}
}
}
}
function initMapAddress2() {
const componentForm = [
'street_number',
'route',
'location',
'locality',
'administrative_area_level_2',
'postal_code',
];
const autocompleteInput = document.getElementById('location2');
const options = {
types: ['(cities)'],
componentRestrictions: { country: 'gb' }
};
const autocomplete2 = new google.maps.places.Autocomplete(autocompleteInput);
autocomplete2.addListener('place_changed', function () {
const place2 = autocomplete2.getPlace();
if (!place2.geometry) {
// User entered the name of a Place that was not suggested and
// pressed the Enter key, or the Place Details request failed.
window.alert('No details available for input: \'' + place2.name + '\'');
return;
}
fillInAddress(place2);
});
function fillInAddress(place2) { // optional parameter
const addressNameFormat = {
'street_number2': 'short_name',
'route2': 'long_name',
'locality2': 'long_name',
'administrative_area_level_22': 'short_name',
'postal_code2': 'short_name',
};
const getAddressComp = function (type) {
for (const component of place2.address_components) {
if (component.types[0] === type) {
return component[addressNameFormat[type]];
}
}
return '';
};
document.getElementById('location2').value = getAddressComp('street_number2') + ' '
+ getAddressComp('route2');
for (const component of componentForm) {
// Location field is handled separately above as it has different logic.
if (component !== 'location2') {
document.getElementById(component).value = getAddressComp(component);
}
}
}
}
<div class="card-container">
<div class="panel">
<div>
<img class="sb-title-icon" src="https://fonts.gstatic.com/s/i/googlematerialicons/location_pin/v5/24px.svg" alt="">
<span class="sb-title">Correspondence Address</span>
</div>
<input type="text" placeholder="Search Address" id="location" />
<input type="text" placeholder="" id="street_number" />
<input type="text" placeholder="" id="route" />
<input type="text" placeholder="" id="locality" />
<div class="half-input-container">
<input type="text" class="half-input" placeholder="" id="administrative_area_level_2" />
<input type="text" class="half-input" placeholder="" id="postal_code" />
</div>
</div>
</div>
<script src="https://maps.googleapis.com/maps/api/js?key=****************Zv_k&libraries=places&callback=initMap&channel=GMPSB_addressselection_v1_cA" async defer></script>
<div class="card-container">
<div class="panel">
<div>
<img class="sb-title-icon" src="https://fonts.gstatic.com/s/i/googlematerialicons/location_pin/v5/24px.svg" alt="">
<span class="sb-title">Location Address</span>
</div>
<input type="text" placeholder="Search Address" id="location2" />
<input type="text" placeholder="" id="street_number2" />
<input type="text" placeholder="" id="route2" />
<input type="text" placeholder="" id="locality2" />
<div class="half-input-container">
<input type="text" class="half-input" placeholder="" id="administrative_area_level_22" />
<input type="text" class="half-input" placeholder="" id="postal_code2" />
</div>
</div>
</div>
<script src="https://maps.googleapis.com/maps/api/js?key=****************Zv_k&libraries=places&callback=initMapAddress2&channel=GMPSB_addressselection_v1_cA" async defer></script>
For anyone else having the same issue, I found a solution here Multiple Address on same page

how to pass textbox target value onchange event and change object properties using hooks

to update the complete object properties by using useState
pass textbox target value onchange event and change object properties using hooks
function ExampleObjectHooks() {
const [name, setname] = useState({ first: '', last: '' });
const onInputNameChange = (e) => {
setname({ first: e.target.value, last: e.target.value });
console.log(name);
}
return (
<div>
<form>
<input type="text" onChange={(e) => onInputNameChange(e)} ></input>
<input type="text" onChange={e => onInputNameChange(e)} ></input>
</form>
{name.first}{name.last}
</div>
);
}
Add an name attribute to each input field, and update the state using the name (key in the code). Node that you need to merge the state of each field by yourself. To so spread the previous state, and override the field you've just updated.
const { useState } = React;
function ExampleObjectHooks() {
const [name, setname] = useState({ first: '', last: '' });
const onInputNameChange = ({ target }) => {
const { name: key, value } = target;
setname(state => ({
...state,
[key]: value
}));
};
return (
<div>
<form>
<input name="first" type="text" onChange={onInputNameChange} ></input>
<input name="last" type="text" onChange={onInputNameChange} ></input>
</form>
{name.first} {name.last}
</div>
);
}
ReactDOM.render(
<ExampleObjectHooks />,
root
);
<script crossorigin src="https://unpkg.com/react#17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#17/umd/react-dom.development.js"></script>
<div id="root"></div>

Unable to render redux form select input choices dynamically

I am trying to populate a select menu in redux forms dynamically.
I've been using the debugging tools in chrome and can see that the 'departments' variable sees the array list
({departments.map(department => <option key={department} value={department}>{department}</option>)}
but the final choice list isn't populating. I'm guessing it has something to do with the renderSelectField function, but I'm not sure what I am overlooking?
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import isValidEmail from 'sane-email-validation';
class SimpleReduxForm extends Component {
constructor(props) {
super(props);
this.onSubmit = this.onSubmit.bind(this);
this.renderSelectField = this.renderSelectField.bind(this);
}
onSubmit = async (data) => {
try {
let response = await fetch('/api/getRecords', {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-type': 'application/json'
}
});
let responseJson = await response.json();
//display success message to user
alert('Form successfully submitted')
return responseJson;
//reset form
} catch (error) {
alert(error);
}
}
renderInputField(field) {
return (
<div className="form-group">
<label htmlFor={field.input.name}>{field.label}</label>
<div className="field">
<input placeholder={field.label} {...field.input} className="form-control" type={field.input.type} />
</div>
</div>
)
}
renderSelectField(field) {
return (
<div className="form-group">
<label htmlFor={field.input.name}>{field.label}</label>
<div className="field">
<select {...field.input}
className="form-control"
defaultselection={field.defaultSelection}
><option>{field.defaultselection}</option></select>
</div>
</div>
)
}
render() {
const { handleSubmit, pristine, reset, submitting, invalid } = this.props;
//Options for select - this should be an AJAX call to a table to get options list
const departments = ["Dept 1", "Dept 2", "Dept 3"]
return (
<form onSubmit={handleSubmit(this.onSubmit)}>
<Field
label="Username"
name="username"
component={this.renderInputField}
type="text"
/>
<Field
label="Email"
name="email"
component={this.renderInputField}
type="email"
/>
<Field
label="Age"
name="num_field"
component={this.renderInputField}
type="text"
/>
<Field
label="Department"
name="department"
defaultselection="Select..."
component={this.renderSelectField}>
{departments.map(department => <option key={department} value={department}>{department}</option>)}
</Field>
<div>
<button type="submit" className="btn btn-primary" disabled={pristine || submitting}>Submit</button>
<button type="button" className="btn btn-warning" disabled={pristine || submitting} onClick={reset}> Clear Values </button>
</div>
</form >
)
}
}
//Validate Errors Before Submission
const validate = (values) => {
//create errors object
const errors = {}
/*Example showing to check is a field contains data
* if no, submission == invalid*/
if (!values.username) {
errors.username = 'Required!'
}
/*check to see if email is provided and that submission is an actual email address*/
if (!values.email) {
errors.email = 'Required!'
} else if (!isValidEmail(values.email)) {
errors.email = 'Invalid Email!'
}
/* Example to show that the length of a field
* can be checked as part of validation */
if (values.num_field < 2) {
errors.num_field = "Must be at least 10 years old"
}
return errors
}
const mapStateToProps = state => ({
SimpleReduxForm: state.form.SimpleReduxForm
});
export default reduxForm({
validate,
form: 'SimpleReduxForm',
enableReinitialize: true,
keepDirtyOnReinitialize: true,
})(connect(mapStateToProps)(SimpleReduxForm));
I figured it out. Just in case anyone else runs into this issue. I needed to add {field.children} into the renderSelectField function. So the final function looks like:
renderSelectField(field) {
return (
<div className="form-group">
<label htmlFor={field.input.name}>{field.label}</label>
<select {...field.input}
className="form-control"
defaultselection={field.defaultSelection}
><option>{field.defaultselection}</option>{field.children}</select>
</div>
)
}

How to send input hidden in React JS?

I have this form, and I would like to send these values. I know we have to use setState() to store data but how does it work for input type="hidden"?
First question: How to store input hidden to setState ?
Second question: How to serialize data like form.serialize() ?
Third question: How to send these serialize values? Ajax or Axios, who is the better?
Here is the code:
handleSubmit(e) {
e.preventDefault();
/**
$.ajax({
url: "post.php",
type: "POST",
data: DATA,
success:function(data) {
}
});
**/
}
<form onSubmit={this.handleSubmit}>
<input type="hidden" name="action" value="login" />
<input type="email" name="email_user" placeholder="Email" />
<input type="password" name="password_user" placeholder="Mot de passe" />
<button type="submit">Login</button>
</form>
The answer is complex for all your questions.
First of all, it depends on the task: if you just want to send asynchonous request to server on form submit, you don't need to use Component state. Here is a link to the relevant section of the documentation. And use refs to access inputs data.
class FormComponent extends React.Component {
constructor(props) {
super(props);
this.onSubmit = this.onSubmit.bind(this);
}
onSubmit(e) {
e.preventDefault();
// Send your ajax query via jQuery or Axios (I prefer Axios)
axios.get('your_url', {
params: {
action: this.actionInput.value,
email: this.emailInput.value,
password: this.passwordInput.value,
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
render() {
return (
<form onSubmit={this.onSubmit}>
<input type="hidden" name="action" value="login"
ref={(input) => { this.actionInput = input }} />
<input type="email" name="email_user" placeholder="Email"
ref={(input) => { this.emailInput = input }}/>
<input type="password" name="password_user" placeholder="Mot de passe"
ref={(input) => { this.passwordInput = input }}/>
<button type="submit">Login</button>
</form>
);
}
}
All data can be stored on React's state, but if you still need to have inputs on your form you can do something like this:
const handleSubmit = e => {
e.preventDefault();
const inputs = Object.values(e.target)
.filter(c => typeof c.tagName === 'string' && c.tagName.toLowerCase() === 'input')
.reduce((acc, curr) => ({ ...acc, [curr.name]: curr.value }), {});
setFormVals({ ...formVals, ...inputs });
}
See the demo below:
const Demo = () => {
const [formValues] = React.useState({});
const handleSubmit = e => {
e.preventDefault();
const inputs = Object.values(e.target)
.filter(c => typeof c.tagName === 'string' && c.tagName.toLowerCase() === 'input')
.reduce((acc, curr) => ({ ...acc, [curr.name]: curr.value }), {});
console.log(inputs);
}
return (
<form onSubmit={handleSubmit}>
<input name="name" placeholder="Name" value={formValues.name} />
<input name="email" placeholder="Email" value={formValues.email} />
<input name="hiddenInput" value="hiddenValue" type="hidden" />
<button type="submit">Submit</button>
</form>
);
}
ReactDOM.render(<Demo />, document.getElementById('demo'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>
<div id="demo"></div>
If you know what the inputs that you need you can do something like this:
const Demo = () => {
const formRef = React.useRef(null);
const [formValues, setFormValues] = React.useState({});
const handleChange = e => {
setFormValues({
...formValues,
[e.target.name]: e.target.value,
});
}
const handleSubmit = e => {
e.preventDefault();
setFormValues({ ...formValues, hiddenInput: formRef.current.hiddenInput.value });
}
return (
<form onSubmit={handleSubmit} ref={formRef}>
<input name="name" placeholder="Name" value={formValues.name} onChange={handleChange} />
<input name="email" placeholder="Email" value={formValues.email} onChange={handleChange} />
<input name="hiddenInput" value="hiddenValue" type="hidden" />
<button type="submit">Submit</button>
<pre>{JSON.stringify(formValues, null, 2)}</pre>
</form>
);
}
ReactDOM.render(<Demo />, document.getElementById('demo'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>
<div id="demo"></div>
Answering your questions:
Since you know how to use component's state you may set the value as : <input type='text' value={this.state.foo} /> or even via props passing <input type='hidden' value={this.props.foo} />
You don't need to serialise anything at all. Use your component's local state or even a state container like Redux or Flux in order to pick the appropriate data. Take a look at this fairly simple example:
var SuperForm = React.createClass({
getInitialState() {
return {
name: 'foo',
email: 'baz#example.com'
};
},
submit(e){
e.preventDefault();
console.log("send via AJAX", this.state)
},
change(e,key){
const newState = {};
newState[key] = e.currentTarget.value;
this.setState(newState)
},
render: function() {
return (
<div>
<label>Name</label>
<input
onChange={(e) => this.change(e,'name')}
type="text"
value={this.state.name} />
<label>Email</label>
<input
onChange={(e) => this.change(e,'email')}
type="text"
value={this.state.email} />
<button onClick={this.submit}>Submit</button>
</div>
);
}});
Demo
AJAX is a set of web development techniques while Axios is a JavaScript framework. You may use jQuery, Axios or even vanilla JavaScript.

Resources