I've been trying to implement the Google Places API to autofill the fields of a simple address form with Antd, but so far, after have chosen a place, the fields won't populate the way I want.
I am using the package react-google-autocomplete
successfully to get what I want.
To test things, I have been focusing on just using 1 field, the city
one.
Right now, my form is decomposed in 2 elements.
NewForm.tsx
const NewForm = (props: Props) => {
const [form] = Form.useForm();
const formRef = useRef<any>(null);
const onFinish = async (values: any) => {
const newAddressData: NewAddressInput = {
name: values.name?.toUpperCase(),
company: values.company?.toUpperCase(),
street1: values.street1.toUpperCase(),
street2: values.street2?.toUpperCase(),
city: values.city.toUpperCase(),
state: values.state.toUpperCase(),
zip: values.zip.toUpperCase(),
country: values.country.toUpperCase(),
phone: values.phone,
notes: values.notes,
};
const onFinishFailed = (errorInfo: any) => {
console.log('Failed:', errorInfo);
if (errorInfo.errorFields.length > 0) {
errorInfo.errorFields.map((field: { errors: string[]; }, index: any) => {
toast.error(field.errors[0] as string);
});
}
};
useEffect(() => {
console.log('form values in useEffect', form.getFieldValue('city'));
}, [form]);
console.log('form values', form.getFieldValue('city'));
return (
<Dashboard>
<Form
ref={formRef}
form={form}
name="newClientForm"
labelCol={{ span: 3 }}
wrapperCol={{ span: 22 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
className={styles.createClientForm}
layout="horizontal"
onValuesChange={(changed, all) => console.log('values change', changed, all)}
onFieldsChange={(first, second) => console.log('fields change', first, second)}
fields={[
{
name: 'city',
value: form.getFieldValue('city')
}
]}
>
<h2>Create a New Client</h2>
<Divider />
<CreateAddressFields />
<Form.Item
style={{ textAlign: 'center' }}
// wrapperCol={{ offset: 4, span: 16 }}
>
<Button
type="primary"
htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
</Dashboard>
);
};
CreateAddressFields.tsx
function CreateAddressFields({ }: Props) {
const [foundAddress, setFoundAddress] = useState<NewAddressInput | null>(null);
const [city, setCity] = useState<string | null>(null);
const inputRef = useRef<any>(null);
const options = {
componentRestrictions: { country: ["ca", "us"] },
fields: ["address_components", "geometry", "icon", "name"],
types: ["address"]
};
// inputRef.current.focus();
const { ref, autocompleteRef } = usePlacesWidget({
apiKey: PLACES_API_KEY,
onPlaceSelected: (place, inputRef, something) => {
console.log('place selected', place);
const address = place.address_components;
let { street1, street2, city, state, zip, country }: NewAddressInput = {
street1: '',
street2: '',
city: '',
zip: '',
state: '',
country: ''
};
if (address) {
console.log('going through found address');
for (const component of address) {
const type = component.types[0];
switch (type) {
case "street_number":
street1 = `${component.long_name} ${street1}`;
break;
case "route": {
street1 += component.short_name;
break;
}
case "postal_code": {
zip = `${component.long_name}${zip}`;
break;
}
case "locality":
city = `${component.long_name}${city}`;
break;
case "administrative_area_level_1": {
state = `${component.short_name}${state}`;
break;
}
case "country":
country = `${component.short_name}${country}`;
break;
default:
break;
}
}
setFoundAddress({ street1, street2, city, state, zip, country });
console.log('results', { street1, street2, city, state, zip, country });
}
},
options
});
const handleChange = (event: any) => {
console.log('name', event.target.name);
const name = event.target.name;
console.log('value', event.target.value);
const value = event.target.value;
setFoundAddress({ ...foundAddress!, [event.target.name]: event.target.value });
if (name === 'city') {
setCity(value);
}
};
return (
<>
<Form.Item
label="Name: "
name="name"
rules={[{ required: true, message: 'Please input your name!' }]}>
<Input
// onChange={handleChange}
/>
</Form.Item>
<Form.Item
label="Company: "
name="company">
<Input />
</Form.Item>
<Form.Item
label="Street Info 1:"
name="street1"
rules={[{ required: true, message: 'Please input your street1!' }]}>
<Input
placeholder=''
ref={(c) => {
inputRef.current = c;
if (c) ref.current = c.input;
}}
// ref={inputRef}
/>
</Form.Item>
<Form.Item
label="Street Info 2:"
name="street2">
<Input />
</Form.Item>
<Form.Item
label="City:"
name="city"
// initialValue={foundAddress?.city ? foundAddress.city : ''}
// getValueFromEvent={handleChange}
getValueProps={(v) => {
return ({ name: 'city', value: v });
}}
rules={[{ required: true, message: 'Please input your city!' }]}>
<Input
onChange={handleChange}
value={city!
// ? foundAddress.city : ''
}
// placeholder={foundAddress?.city}
/>
</Form.Item>
{/* <input
name={"city"}
value={foundAddress?.city}
placeholder={"City"}
onChange={handleChange}
/> */}
<Form.Item
label="State:"
name="state"
rules={[{ required: true, message: 'Please input your state!' }]}>
<Input />
</Form.Item>
<Form.Item
label="Zip:"
name="zip"
rules={[{ required: true, message: 'Please input your zip!' }]}>
<Input />
</Form.Item>
{/* {countriesList && ( */}
<Form.Item
label="Country:"
name="country"
rules={[{ required: true, message: 'Please choose your country!' }]}>
<Input />
</Form.Item>
{/* )} */}
<Form.Item
label="Phone:"
name="phone"
rules={[{ required: true, message: 'Please input your phone number!' }]}>
<Input />
</Form.Item>
<Form.Item
label="Notes:"
name="notes">
<Input />
</Form.Item>
</>
The suggestion is triggered when typing in street1
field. Once a place is selected, it successfully sets the state variable foundAddress
. But none of the other fields (in this test case, city) get populated with the selected value.
I've tried quite a few things:
Form.Item
, such as initialValue
, getValueFromEvent
, getValueProps
.Input
componentForm
component: onValuesChange
, onFieldsChange
, fields
.city
field.The field never gets updated.
On the other hand, if I use a simple <input>
instead, I tested and got the value showing when the state variable is populated.
Also, if I fill the placeholder
of the <Input>
as placeholder={foundAddress?.city}
, it does work after selecting an address properly as expected.
What am I doing wrong in value handling with this Antd form?
Update form fields using form.setFieldValue("key", value)