React-Final-Form how to pass props location.search to function - reactjs

I've been using React-Final-Form for the last few days but I have a lot of issues.
In my main function, PasswordReset, I need the take the prop 'location.search' and pass it to the custom 'handleSubmitOnClick' in order to handle the outcome on submit.
Here the main function:
const handleSubmitOnClick = ({ // I need the location.search to be passed here as prop
password,
password_confirmation,
}) => {
const url = 'http://localhost:3000/api/v1/users/passwords';
const headers = {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
}
}
const data = {
"user": {
"reset_password_token": location.search,
"password": password,
"password_confirmation": password_confirmation,
}
}
axios.post(url, data, headers)
.then(response => console.log(response))
.catch(error => console.log('error', error)))
}
const PasswordReset = ({
location //<==== I need to pass this to 'handleSubmitOnClick' function
}) =>
<Fragment>
<h1>Password Reset page</h1>
<Form
onSubmit={handleSubmitOnClick}
decorators={[focusOnError]}
>
{
({
handleSubmit,
values,
submitting,
}) => (
<form onSubmit={handleSubmit}>
<Field
name='password'
placeholder='Password'
validate={required}
>
{({ input, meta, placeholder }) => (
<div className={meta.active ? 'active' : ''}>
<label>{placeholder}</label>
<input {...input}
type='password'
placeholder={placeholder}
className="signup-field-input"
/>
{meta.error && meta.touched && <span className="invalid">{meta.error}</span>}
{meta.valid && meta.dirty && <span className="valid">Great!</span>}
</div>
)}
</Field>
<Field
name='password_confirmation'
placeholder='Confirm password'
validate={required}
>
{({ input, meta, placeholder }) => (
<div className={meta.active ? 'active' : ''}>
<label>{placeholder}</label>
<input {...input}
type='password'
placeholder={placeholder}
className="signup-field-input"
/>
{meta.error && meta.touched && <span className="invalid">{meta.error}</span>}
{meta.valid && meta.dirty && <span className="valid">Great!</span>}
</div>
)}
</Field>
<button
type="submit"
className="signup-button"
disabled={submitting}
>
Submit
</button>
</form>
)}
</Form>
</Fragment>
export default PasswordReset;
Any help is REALLY appreciated. A bad answer is better than no answers. Thanks in advance.

You can curry your function to have location updated everytime.
Currying method: (preferred by linters)
const handleSubmitOnClick = (location) => ({ //location would come from PasswordReset every time there's a re-render
^^^^^^^^
password,
password_confirmation,
}) => {
...
}
const PasswordReset = ({
location //<==== I need to pass this to 'handleSubmitOnClick' function
}) =>
<Fragment>
<h1>Password Reset page</h1>
<Form
onSubmit={handleSubmitOnClick(location)} // <--- This will update location on every re-render
decorators={[focusOnError]}
>
{ ... }
</Form>
</Fragment>
export default PasswordReset;
Inline function method:
Alternatively you can use what other answer provided but you still need to update your handleSubmitOnClick function to accept your location prop. It will create new function on every re-render, but because inline functions are bad practice deemed by linters I prefer currying method.
<Form
onSubmit={() => handleSubmitOnClick(location)} // <--- This will create new function on every re-render
decorators={[focusOnError]}
>

<Form
onSubmit={() => handleSubmitOnClick(location)}
decorators={[focusOnError]}
>
Wrap it in an anonymous function that once called, calls your function with the required param, which would be location in this case.
After that the function would have an extra argument:
handleSubmitOnClick = location => ({..props})

Related

Leadspedia Form Submission does not work with onSubmit

I have a form in React that I'm trying to submit to Leadspedia, but I'm seeing strange behavior. The instructions from Leadspedia API shows an example of using the method and action options to send the form. I'd like to use the onSubmit event handler to have more control of the form, but for some reason that returns with an error. Using their example submits correctly. Here is my code:
const postData = async (url = '', data = {}) => {
const response = await fetch(url, {
method: 'POST',
body: JSON.stringify(data),
});
return response.json();
}
const handleSubmit = async (e) => {
e.preventDefault();
const url = "*leadspedia end point*";
const data = formValues;
postData(url, data)
.then((data) => {
console.log(data)
})
.catch(error => {
console.log(error)
})
resetForm(
Here is my form:
<form
style={{ width: '100%'}}
onSubmit={handleSubmit}
id="lp_form"
action="*leadspedia endpoint*"
method="post"
>
<div>
{formSections?.[formStep]?.fields?.map((field, index) => (
renderInput(field, index)
))}
{Object.keys(formValues).map((key, index) => (
<input key={index} type="hidden" name={key} value={formValues[key]} />
))}
<input type="hidden" id="lp_offer_id" name="lp_offer_id" value={offerId} />
<input type="hidden" id="lp_campaign_id" name="lp_campaign_id" value={campaignId} />
<input type="hidden" id="lp_campaign_key" name="lp_campaign_key" value={campaignKey} />
</div>
<div>
{formStep === 9 && (
<Button type="submit" variant="primary">
Submit
</Button>
)}
</div>
</form>
Submitting without the handleSubmit function works perfectly fine. However, submitting the form with the handleSubmit function returns a response that says Invalid campaign key or id. I've checked the values multiple times and it's the correct key and id. Am I missing something the handleSubmit function that would cause this error?

How do I implement a custom handleChange function on Formik?

In an input element, handleChange function would receive the event object from the onChange event. How do I create a custom handleChange function for non-input fields like the following?
import React from 'react';
import { useFormik } from "formik";
const SomeForm = () =>
{
const { handleChange, handleSubmit, values } = useFormik({
initialValues: {
type: `company`, name: ``,
},
onSubmit: values => {
console.log(JSON.stringify(values, null, 2));
},
});
return (
<div>
<form onSubmit={ handleSubmit }>
<label>Type</label>
<ul>
<li className={ values.type === `company` && `active` }
onClick={() => handleChange(/* some custom handle change */)} >
Company
</li>
<li className={ values.type === `individual` && `active` }
onClick={() => handleChange(/* some custom handle change */)} >
Individual
</li>
</ul>
<label>Full Name</label>
<input type="text"
name="name"
value={ value.name }
onChange={ handleChange } />
</form>
</div>
)
};
export default SomeForm;
use setField('fieldName',value) method of form object provided in render props pattern of Field component.
I think this is what you're after. You can add your custom code after field.onChange(e).
// Custom field
const MyTextField = ({ label, ...props }) => {
const [field, meta] = useField(props);
return (
<>
<input {...field} {...props}
onChange={e => {
// The original handler
field.onChange(e)
// Your custom code
console.log('I can do something else here.')
}}
className={ meta.error && 'is-invalid'}` } />
{meta.touched && meta.error && (
<div>{meta.error}</div>
)}
</>
);
};
And use it like so
<MyTextField name="entry" type="text" />

Issue to submit CSV file to DB via POST Axios & React-Final-Form

I need to save the content of a CSV into a database table by using React-Final-Form and Axios.
I have tried to create a simple HTML without using Final-Form or Axios and the submission to the DB works fine.
The problem is when I try to pass the content of the CSV to a function which will handle the POST call.
See code below:
import React, { Fragment } from "react";
import { Form, Field } from "react-final-form";
import createDecorators from "final-form-focus";
const handleSubmitOnClick = file => {
const url = 'http://localhost:3000/api/v1/invitations/upload';
const data = new FormData();
data.append('file', new File([file], { type: 'text/csv' }));
return axios.post(url, data, {
headers: {
'content-type': 'multipart/form-data'
}
})
.then(response => console.log(response))
.catch(error => console.log(error));
}
const JoinTesting = () =>
<Fragment>
<h1>Join Testing Page</h1>
<Form
onSubmit={handleSubmitOnClick}
decorators={[focusOnError]}
>
{
({
handleSubmit,
values,
submitting,
}) => (
<form onSubmit={handleSubmit} encType="multipart/form-data">
<Field
name='invitation[file]'
placeholder='Upload csv file'
validate={required}
>
{({ input, meta, placeholder }) => (
<div className={meta.active ? 'active' : ''}>
<label>{placeholder}</label>
<input {...input}
type='file'
placeholder={placeholder}
className="join-field-input"
/>
{meta.error && meta.touched && <span className="invalid">{meta.error}</span>}
{meta.valid && meta.dirty && <span className="valid">Great!</span>}
</div>
)}
</Field>
<button
type="submit"
className="join-button"
disabled={submitting}
>
Submit
</button>
<pre>{JSON.stringify(values, 0, 2)}</pre>
</form>
)}
</Form>
</Fragment>
export default JoinTesting;
If I remove ALL the above and I just use this HTML within my JoinTesting component, it works fine but I can't handle the errors (if any)
<form action="http://localhost:3000/api/v1/invitations/upload" method="post" encType="multipart/form-data">
Select CSV to upload:
<input type="file" name="invitation[file]" id="fileToUpload" />
<br></br>
<input type="submit" value="Upload CSV" name="submit" />
</form>
PLEASE NOTE: The CSV file has only a simple 1 column with a sequence of email addresses.
This is what the POST request expects:
Headers:
Content-Type: application/json
Accept: application/json
Body
{
"invitation": {
"file": "Email\nuser_1#gmail.com\nuser_2#gmail.com\nuser_3#gmail.com\nuser_4#gmail.com\n"
}
}
The API response expected for a success call is:
{
"success": true,
"emails": [
"user_1#gmail.com",
"user_2#gmail.com",
"user_3#gmail.com",
"user_4#gmail.com"
]
}
I hope someone can help.
George
If you're not using html form + HTTP POST + encType="multipart/form-data", then you'll need to handle the file upload yourself.
One way to do it: get reference to the input component, listen to changes, when a change happens get the filename from the input reference, read the file, save the data. Here's a component for that:
function FileInput(props) {
const fileInput = useRef(null);
const setRef = ref => {
fileInput.current = ref;
};
async function handleInputChange() {
const { files } = fileInput.current;
props.onChange(files[0]);
}
return (
<input
ref={setRef}
type="file"
placeholder={props.placeholder}
className="join-field-input"
onChange={handleInputChange}
/>
);
}
Use this within the Field component, and the form state will contain the file:
<Field name="invitation[file]" placeholder="Upload csv file">
{({ input, meta, placeholder }) => (
// ...
<FileInput {...input} placeholder={placeholder} />
// ...
)}
</Field>
Also the handleSubmitOnClick gets the whole values object. Your values should look something like this:
values = { invitation: { file: {} } }
So, change the handleSubmitOnClick function to:
const handleSubmitOnClick = values => {
const data = new FormData();
const { file } = values.invitation;
data.append('file', file, file.name);
// ...
}
Here's a codesandbox.

Pass input values with React-Final-Form to Axios POST

I have a login page.
Fields: username and password.
On form submit I want to pass the 2 input values to a function which will handle a POST call via Axios API.
Because I am using React-Final-Form, I don't see anyone using refs for the inputs in order to collect the data.
Final-Form provides values as props, but I can't pass them to my external handleClickSignIn function.
const handleClickSignIn = () => {
axios.post(url, data, {
headers: headers
})
.then(response => console.log(response))
.catch(err => console.log(err))
}
const focusOnError = createDecorators();
const SignIn = () =>
<Fragment>
<h1>Sign In page</h1>
<Form
onSubmit={handleClickSignIn}
decorators={[focusOnError]}
>
{
({
handleSubmit,
values,
submitting
}) => (
<form onSubmit={handleSubmit}>
<Field
name='email'
placeholder='Email'
validate={required}
>
{({ input, meta, placeholder }) => (
<div className={meta.active ? 'active' : ''}>
<label>{placeholder}</label>
<input {...input}
type='email'
placeholder={placeholder}
className="signin-field-input"
/>
etc...
you should look at the documentation
onSubmit is a function that will be called with the values of your form
So handleClickSignIn will retrieve the form values in its first argument
const handleClickSignIn = (values) => {
// do what you want with the form values
axios.post(url, values, {headers: headers})
.then(response => console.log(response))
.catch(err => console.log(err))
}

How to set state for text box in functional component

I am working on React JS. I have one text-box component and I want to show some default value in it. After that, the user should be allowed to change the value. Now I am unable to change the value. The text box is behaving like read-only. Below is my code
const EditStyleFormComponent = ({
submitting,
invalid,
}) => (
<form className={className} onSubmit={handleSubmit}>
<h2>LSPL (Low Stock Presentation Level)</h2>
<Line />
<InputGroup>
<TextFieldWithValidation name="lsplMan" label="LSPL Manual" input={{ onChnage:'', value: 'Current' }} />
</InputGroup>
</form>
);
Below is my TextFieldWithValidation code.
export const TextFieldWithValidationComponent = ({
meta,
input,
noStyles,
...otherProps
}) => (
<TextField
state={noStyles ? textFieldStates.DEFAULT : getState(meta)}
errorMessage={meta.touched ? meta.error : null}
{...input}
{...otherProps}
/>
);
Below is my TextField code.
const TextField = ({
className,
label,
description,
state,
errorMessage,
isEditable,
spaceAtBottom, // Not used, but we don't want it in otherProps
...otherProps
}) => {
const inputId = _.uniqueId();
return (
<div className={className}>
{label &&
<label htmlFor={inputId}>{label}</label>
}
<div className="input-group" id={isEditable ? 'editable' : 'readonly'}>
<input
id={inputId}
readOnly={!isEditable}
{...otherProps}
/>
{getStatusIcon(state)}
{errorMessage &&
<Error>{errorMessage}</Error>
}
{description &&
<Description>{description}</Description>
}
</div>
</div>
);
};
Can someone help me to fix this issue? Any help would be appreciated. Thanks
You can use State Hook for manage state in functional component.
Example :
const Message = () => {
const [message, setMessage] = useState( '' );
return (
<div>
<input
type="text"
value={message}
placeholder="Enter a message"
onChange={e => setMessage(e.target.value)}
/>
<p>
<strong>{message}</strong>
</p>
</div>
);
};
Yu defined onChange as empty string in EditStyleFormComponent component. So on any change input component just do nothing.
onChange should be some function that will update value.
If you want to use functional components there are two possible solutions:
Lift state up to parent component of EditStyleFormComponent (in case parent is class based component)
Use React Hooks like so (just example!)
const EditStyleFormComponent = ({
submitting,
invalid,
}) => {
const [inputValue, setInputValue] = useState ('Current'); // default value goes here
return <form className={className} onSubmit={handleSubmit}>
<h2>LSPL (Low Stock Presentation Level)</h2>
<Line />
<InputGroup>
<TextFieldWithValidation name="lsplMan" label="LSPL Manual" input={{ onChnage: (e) => { setInputValue(e.target.value); }, value: inputValue }} />
</InputGroup>
</form>
};

Resources