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

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.

Related

Country State City Dropdown list is not working using React Hooks

I'm trying to create Dropdown list for Country, State and City using React Hooks. I'm passing country, state and city records from mysql database by using Axios API with useEffect() Hook. I can able to populate the country names but after selecting country name, I'm not able to select the state name because it is not showing any state names.
This is my React Functional Component:
import React, { useState,useEffect } from 'react'
import axios from 'axios';
import { Link,useParams } from 'react-router-dom';
export default function AddStore() {
const{c_id} = useParams();
const{s_id} = useParams();
const [getCounty, setCounty] = useState([]);
const[countryId,setCountryId] = useState('');
const [getState, setState] = useState([]);
const [stateId, setStateId]= useState('');
const [getCity, setCity] = useState([]);
useEffect( ()=>{
const loadCountry = async() => {
const res = await axios.get(`http://localhost:8080/country/all`);
setCounty(res.data);
}
loadCountry();
},[]);
const handleCountry=(event)=>{
const dt = event.target.value;
setCountryId(dt);
}
useEffect( ()=>{
const loadState = async() => {
const res = await axios.get(`http://localhost:8080/state/${c_id}`);
setState(res.data);
}
loadState();
},[countryId]);
const handleState=(event)=>{
const getstateid= event.target.value;
setStateId(getstateid);
}
useEffect( ()=>{
const loadCity = async() => {
const res = await axios.get(`http://localhost:8080/city/${s_id}`);
setCity(res.data);
}
loadCity();
},[stateId]);
return (
<div className="container">
<div className="row">
<div className="mb-3">
<label htmlFor="Country" className="form-label">Country</label>
<select name="country" className="form-control"
onChange={(e)=>handleCountry(e)}>
<option>--Select Country--</option>
{
getCounty &&
getCounty !== undefined ?
getCounty.map((ctr,index) => {
return(
<option key = {index} value = {ctr.c_id}>{ctr.c_name}</option>
)
})
:"No Country"
}
</select>
</div>
<div className="mb-3">
<label htmlFor="State" className="form-label">State</label>
<select
name="state"
className="form-control"
onChange={(e)=>handleState(e)}>
<option>--Select State--</option>
{
getState &&
getState !== undefined ?
getState.map((st,index) => {
return(
<option key = {index} value = {st.id}>{st.name}</option>
)
})
:"No State"
}
</select>
</div>
<div className="mb-3">
<label htmlFor="City" className="form-label">City</label>
<select
name="city"
className="form-control">
<option>--Select City--</option>
{
getCity &&
getCity !== undefined ?
getCity.map((st,index) => {
return(
<option key = {index} value = {st.id}>{st.name}</option>
)
})
:"No City"
}
</select>
</div>
<button type="submit" className="btn btn-outline-primary">Submit</button>
<Link className="btn btn-outline-danger mx-2" to="/">Cancel</Link>
</div>
</div>
);
}
And the controllers:
#GetMapping("/{c_id}")
public List<State> getStateByCountry(#RequestParam(value = "c_id", required= false) Integer c_id){
return stateService.findByCountry(c_id);
}
#GetMapping("/{s_id}")
public List<City> getCityByState(#RequestParam(value = "s_id", required= false) Integer s_id){
return cityService.findByState(s_id);
}

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>
);
}

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;

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 work with axios.put and react?

I am trying create a simple crud system with react redux and form-redux.
The code below but does not work and gives error.
First I created an action for update and then created a reducer for that.
And then created component to use the action.
Let me know how to get this to work.
//-------------action--------------
export const EDIT_POST = 'EDIT_POST';
export const editPost = (id) => {
const request = axios.put(`${BOOK_URL}/books/${id}`);
return {
type: EDIT_POST,
payload: id,
}
};
//---------------- reducer-----------------
case EDIT_POST: {
return {...state, post: action.payload.data}
}
//----------------route--------------
<Route path='/posts/edit/:id' component={PostEdit}/>
//-------------------PostEdit---------------
class PostEdit extends Component {
componentDidMount = () => {
this.props.editPost(this.props.match.params.id);
console.log(this.props.editPost(this.props.match.params.id));
};
renderField = field => {
const {meta: {touched, error}} = field;
const className = `form-group ${touched && error ? 'has-danger' : ''}`;
return (
<div className='has-danger'>
<label>{field.label}</label>
<input type="text" {...field.input} className="form-control"/>
<div className="text-help">
{touched ? error : ''}
</div>
</div>
);
};
render() {
const {handleSubmit} = this.props;
return (
<form onSubmit={handleSubmit(this.onSubmitForm)}>
<Field name="title" label="Title" component={this.renderField}/>
<Field name="author" label="Author" component={this.renderField}/>
<Field name="description" label="Description" component={this.renderField}/>
<Field name="publicationDate" label="PublicationDate" component={this.renderField}/>
<button type='submit' className="btn btn-primary">Submit</button>
<Link to='/' className='btn btn-danger'>Cancel</Link>
</form>
);
}
}
export default reduxForm({
form :'updateForm'
})(connect(null, {editPost})(PostEdit));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Could you tell what error you are getting?
You have to change your action like
export const fetchPosts = () => {
return (dispatch) => {
axios.get(`${BOOK_URL}/books`).then((response) => {
return dispatch({
type: FETCH_POSTS,
payload: // your response here
});
})
}
}

Resources