Formik does not update value from input - formik

I am trying to add Form to my application, so I decided to pick formik and I ran into a little problem
I have following components:
After typing something in input, I am clicking submit and alert appears with empty data like:
{
someName: ''
}
Why someName does not update?
const SearchInput = ({name, ...props}) => {
const [field] = useField(name);
return (
<Styled.Wrapper>
<Styled.Input {...field} {...props} placeholder="Search" />
</Styled.Wrapper>
);
};
const Form = () => {
return (
<Formik
initialValues={{
someName: '',
}}
onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
}}
>
{(props: FormikProps<Values>) => (
<FormikForm>
<SearchInput
name="someName"
type="text"
label="Some Name"
onChange={props.handleChange}
value={props.values.jobName}
/>
<button type="submit">Submit</button>
</FormikForm>
)}
</Formik>
)
};
export default Form;

Related

Formik - TextField does not accept numeric value when using react-number-format

I'm using react-number-format library if numeric values is set to TextField it will not show any error after reset the form.
t should accept the numeric values also like other string values.
Here is my code you are reproduce error from this.
Formik Form
<Formik
enableReinitialize
initialValues={{
area: "",
password: "",
}}
validate={(values) => {
const errors: Partial<Values> = {};
if (!values.area) {
errors.area = "Required area";
}
return errors;
}}
onSubmit={(values, { setSubmitting, resetForm }) => {
setTimeout(() => {
setSubmitting(false);
console.log(JSON.stringify(values, null, 2));
resetForm();
}, 500);
}}
>
{({ submitForm, isSubmitting }) => (
<Form>
<Field
component={TextField}
name="area"
label="area"
InputProps={{
inputComponent: NumberField,
}}
/>
<br />
<Field
component={TextField}
type="password"
label="Password"
name="password"
/>
{isSubmitting && <LinearProgress />}
<br />
<Button
variant="contained"
color="primary"
disabled={isSubmitting}
onClick={submitForm}
>
Submit
</Button>
</Form>
)}
</Formik>
NumberField
import NumberFormat from "react-number-format";
interface NumberFieldProps {
name: string;
inputRef: (instance: NumberFormat<any> | null) => void;
onChange: (event: {
target: { name: string; value: number | undefined };
}) => void;
}
export default function NumberField(props: NumberFieldProps) {
const { inputRef, onChange, ...other } = props;
return (
<NumberFormat
{...other}
getInputRef={inputRef}
onValueChange={(values) => {
onChange({
target: {
name: other.name,
value: values.floatValue,
},
});
}}
/>
);
}
Click on submit button and you will see Required area error, Set value in area field and submit form, it submit the form and reset it after that click again on submit button you will see it will not give you Required area error. I don't know why this happen.
Now change value: values.floatValue to value: values.value in NumberField file and everything work well. I don't know why it is not working when I set floatValue I need numeric values not string.

Form is not rendered

I'm making a todo app and using useState to pass value to the form then submit the todo but for some reasons my todo form is not render and i don't know what is missing in my codes, please help me to check! Thank you so much!
import React, { useState } from "react";
function Todo({ todo, index }) {
console.log("hiiii");
return (
<div>
<p>{todo.text}</p>
</div>
);
}
function todoForm(addTodo) {
const [value, setValue] = useState("");
handleSubmit = (e) => {
e.preventDefault();
if (!value) return;
addTodo(value);
setValue("");
};
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="add new todo"
value={value}
onChange={(e) => {
setValue(e.target.value);
}}
/>
</form>
</div>
);
}
function App() {
const [todos, setTodos] = useState([
{
text: "eat lunch",
isCompleted: false
},
{
text: "do homework",
isCompleted: false
},
{
text: "go to school",
isCompleted: false
}
]);
addTodo = (text) => {
console.log("hey");
const newTodos = [...todos, { text }];
setTodos(newTodos);
};
return (
<div>
<div>
{todos.map((todo, index) => {
return <Todo key={index} index={index} todo={todo} />;
})}
</div>
<div>
<todoForm addTodo={addTodo} />
</div>
</div>
);
}
export default App;
Link sandbox: https://codesandbox.io/s/serverless-bash-ef4hk?file=/src/App.js
JSX tags must be uppercased in order to be properly parsed by the compiler as a React component.
Instead of todoForm, use TodoForm.
Capitalized types indicate that the JSX tag is referring to a React component. These tags get compiled into a direct reference to the named variable, so if you use the JSX expression, Foo must be in scope.
From: https://reactjs.org/docs/jsx-in-depth.html#specifying-the-react-element-type
Also, you need to destructure props inside TodoForm in order to gain access to addTodo:
// Bad
function TodoForm(addTodo) {...}
// Good
function TodoForm({addTodo}) {...}
You should also assign you handlers to consts:
// Bad
addTodo = (text) => {...};
// Good
const addTodo = (text) => {...};
your problem is solved it
APP.JS
import React, { useState } from "react";
function Todo({ todo, index }) {
console.log("hiiii");
return (
<div>
<p>{todo.text}</p>
</div>
);
}
function todoForm(addTodo) {
const [value, setValue] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
if (!value) return;
addTodo(value);
setValue("");
};
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="add new todo"
value={value}
onChange={(e) => {
setValue(e.target.value);
}}
/>
</form>
</div>
);
}
function App() {
const [todos, setTodos] = useState([
{
text: "eat lunch",
isCompleted: false
},
{
text: "do homework",
isCompleted: false
},
{
text: "go to school",
isCompleted: false
}
]);
const addTodo = (text) => {
console.log("hey");
const newTodos = [...todos, { text }];
setTodos(newTodos);
};
return (
<div>
<div>
{todos.map((todo, index) => {
return <Todo key={index} index={index} todo={todo} />;
})}
</div>
<div>
{todoForm(addTodo)}
</div>
</div>
);
}
export default App;

Change the options passed to formik (Field) form after selecting the value from other dropdown

Below is the code which I am using. When I am changing the data for Division the state of district list is changed but it is not shown in the form. I need to click on the form and the changed state data is reflected. I want it to get reflected once the state is changed.
function Input(props) {
const { label, name, ...rest } = props
return (
<div>
{/* <label htmlFor={name}>{label}</label> */}
<Field id={name} name={name} {...rest} />
<ErrorMessage name={name} component={TextError}/>
</div>
)
}
function Select(props) {
const { label, name, options, ...rest } = props
return (
<div className="form-group">
{/* <label htmlFor={name}>{label}</label> */}
<Field as='select' id={name} name={name} {...rest} >
{
options.map(option => {
return(
<option key={option.value} value={option.value}>
{option.key}
</option>
)
})
}
</Field>
<ErrorMessage name={name} component={TextError}/>
</div>
)
}
function Test() {
const [divisions, setDivisions] = useState([])
const [districts, setDistricts] =useState([])
const [blocks, setBlocks] = useState([])
const [initialValues,setInitialValues] = useState({
divisionCode:"",
districtCode:"",
blockCode : "",
name : "",
})
const validationSchema = Yup.object({
divisionCode :Yup.string().required('Required!!'),
districtCode :Yup.string().required('Required!!'),
blockCode : Yup.string().required('Required!!'),
name : Yup.string().required('Required!!'),
})
async function getDivisionList() {
try {
const res = await axios.get("APIURL")
return (res.data.response)
} catch (error) {
console.error(error);
}
}
function getDistrictList(divisionCode) {
axios.get("APIURL")
.then(res=>{
setDistricts(res.data.response)
return res.data.response[0].value
})
}
function getBlockList(districtCode) {
axios.get("APIURL")
.then(res => {
setBlocks(res.data.response)
})
}
useEffect(() => {
getDivisionList().then(res => {
setDivisions(res)
});
}, [])
const onSubmit = values => {
console.log('Form data ',values)
console.log('Saved data ',JSON.parse(JSON.stringify(values)))
}
return (
<Formik
initialValues = {initialValues}
validationSchema = {validationSchema}
onSubmit = {onSubmit}
>
{
formik => <Form>
<Select control='select' label='Division' onBlur={e => { var data = getDistrictList(e.currentTarget.value)}} name='divisionCode' options={divisions} />
<Select control='select' label='District' onBlur={e => { getBlockList(e.currentTarget.value)}} name='districtCode' options={districts} />
<Select control='select' label='Block' name='blockCode' options={blocks} />
<Input control='input' type='text' label='Name' name='name' />
<button type="submit" disabled={!formik.isValid}>Submit</button>
</Form>
}
</Formik>
)
}
export default Test
Thanks in Advance. It will be very helpful.

react hook, validate Form with reduxForm

I Have external component managing my input Field and throws an error if no input is made.
On submit of form previously with class component along with reduxForm effect, this would throw an error of missing input, am wondering how to achieve this with hooks since submission passes whether i have input or Not.
import ConstructField from '../components.render';
const ActivitiesForm = () => {
const handleSubmit_ = () => {
console.log({ activityName });
};
const [activityName, setActivityName] = useState(null);
const handleInputName = (e) => setActivityName(e.target.value);
const { items } = useSelector((state) => ({
items: state.items,
}));
const { register, handleSubmit, errors, control } = useForm();
return (
<div>
<Form onSubmit={handleSubmit(handleSubmit_)} className='ui form'>
<Form.Group widths='equal'>
<Field
component={ConstructField('input')}
onChange={handleInputName}
label='Activity Name'
name='activityName'
placeholder='Activity Name'
validate={required}
/>
</Form.Group>
<br />
<Form.Group inline>
<Button.Group>
<Button primary>Save</Button>
<Button.Or />
<Button positive onClick={goBackButton}>
Go Back
</Button>
</Button.Group>
</Form.Group>
</Form>
</div>
);
};
const required = (value) => (value ? undefined : 'this field is required');
const activityform = reduxForm({
form: 'activityform',
enableReinitialize: true,
})(ActivitiesForm);
export default activityform;

I am using antd deign to show select option but select cant read id provided and also cannot update onChange

I am using antd deign to show select option but select cant read id provided and also cannot update onChange.
import React from "react";
const data = {
orgName: "",
orgRegNo: "",
orgType: "",
orgTypes: [
{ id: "1", name: "Vendor" },
{ id: "2", name: "Supplier" },
{ id: "3", name: "Vendor and Supplier" }
]
};
export const MyContextTSX = React.createContext(data);
const Store = (props: any) => {
return (
<MyContextTSX.Provider value={data}>{props.children}</MyContextTSX.Provider>
);
};
export default Store;
//Next page of React signup
const signinData = useContext(MyContextTSX);
const [values, setValues] = useState(signinData);
<Select
id={values.orgTypes.id} //shows error while showing id
// name={values.orgTypes.name}
defaultValue="Choose"
style={{ width: 150 }}
onChange={(value: any) => //cant perform onChange
setValues({ ...value, name: value })
}
>
{values.orgTypes.map((option: any) => (
<Option
key={option.id}
value={option.name}
// onChange={handleChange}
>
{option.name}
</Option>
))}
</Select>
I am using antd deign to show select option but select cant read id provided and also cannot update onChange.
Link to CodeSandbox
There are few issues in your code.
Firstly, you are trying to access id from orgTypes which is an array. Instead you can defined a normal id.
Secondly, You need to have a contextProvider wrapping your App component
Third. You need to update state in the correct format such that you are not updating the data but the selected value. For that you need to have a state for selected value
Relavant code
index.js
ReactDOM(
<Store>
<App />
</Store>,
document.getElementById("root")
);
useForm.js
import { useContext, useState } from "react";
import { MyContextTSX } from "./Store";
const useForm = ({ callback }) => {
const values = useContext(MyContextTSX);
const [selected, setSelected] = useState({});
return { values, selected, setSelected };
};
export default useForm;
Register.js
const Register = () => {
const { values, selected, setSelected } = useForm({});
return (
<React.Fragment>
<Select
id={"select"} //shows error here
defaultValue="Choose"
style={{ width: 150 }}
onChange={(
value: any //what to do here ?
) => setSelected(selected)} //what to do here ?
>
{values.orgTypes.map((option: any) => (
<Option key={option.id} value={option.name}>
{option.name}
</Option>
))}
</Select>
<button onClick={() => console.log(values.orgTypes)}>Test</button>
</React.Fragment>
);
};
There are many problems with your code:
id={values.orgTypes.id} // orgTypes is an array, use values.orgTypes[0].id
---
onChange={(
value: any // value is the Select.Option value
) => setValues({ ...value, name: value })} // What exatcly you trying to do here?
Moreover, you don't specify types (and using Typescript).
Check this working example (Javascript):
const data = {
orgName: '',
orgRegNo: '',
orgType: '',
orgTypes: [
{ id: '1', name: 'Vendor' },
{ id: '2', name: 'Supplier' },
{ id: '3', name: 'Vendor and Supplier' }
]
};
const MyContextTSX = React.createContext(data);
function Signup() {
const signinData = useContext(MyContextTSX);
const [selected, setSelected] = useState();
return (
<div>
<h1>Selected: {selected}</h1>
<Select
defaultValue="Choose"
style={{ width: 150 }}
onChange={value => setSelected(value)}
>
{signinData.orgTypes.map(option => (
<Select.Option key={option.id} value={option.name}>
{option.name}
</Select.Option>
))}
</Select>
</div>
);
}
Demo:
Tweaking little bit #Dennish Vash answer and the signup function can also be written like this
function Signup() {
const signinData = useContext(MyContextTSX);
const [selected, setSelected] = useState();
return (
<div>
<h1>Selected: {selected}</h1>
<Select
defaultValue="Choose"
style={{ width: 150 }}
onChange={value => setSelected(value)}
>
{signinData.orgTypes.map(option => (
<Option value="{option.id}">{option.name}</Option>
))}
</Select>
</div>
);
}
Reference: https://github.dev/ant-design/ant-design/tree/master/components/select/demo

Resources