React Final Form with react-places-autocomplete - reactjs

I've looked at a bunch of other similar questions, but none are answered!
So far I have created a standard record-level which looks like this: https://final-form.org/docs/react-final-form/examples/record-level-validation
I am using React Final Form with react-places-autocomplete. I want to include the selections of react-places-autocomplete to show in the values as seen in the link above, when you enter information into the fields.
I have tried to add the following code based on react-places-autocomplete:
<Field name="location">
{({input, meta}) => (
<PlacesAutocomplete
value={address}
onChange={setAddress}
onSelect={handleSelect}
>
{({ getInputProps, suggestions, getSuggestionItemProps, loading }) => (
<div>
<p> latitude: {coordinates.lat}</p>
<p> longitude: {coordinates.lng}</p>
<input
{...input}
{...getInputProps({
placeholder: 'Search Places ...',
className: 'location-search-input',
})}
/>
<div className="autocomplete-dropdown-container">
{loading && <div>Loading...</div>}
{suggestions.map(suggestion => {
const className = suggestion.active
? 'suggestion-item--active'
: 'suggestion-item';
// inline style for demonstration purpose
const style = suggestion.active
? { backgroundColor: '#fafafa', cursor: 'pointer' }
: { backgroundColor: '#ffffff', cursor: 'pointer' };
return (
<div
{...getSuggestionItemProps(suggestion, {
className,
style,
})}
>
<span>{suggestion.description}</span>
</div>
);
})}
</div>
</div>
)}
</PlacesAutocomplete>
)}
</Field>
I'm wondering how I add the input of the placeautocomplete into this value here:
<pre>{JSON.stringify(values, undefined, 2)}</pre>

Sorry my answer is old, but try using react-google-places-autocomplete. Much better here is how you can use it....
<Field name="city">
{({ input, meta }) => (
<div style={{ width: '100%' }}>
<GooglePlacesAutocomplete
selectProps={{
value: input.value,
onChange: e => {
input.onChange(e.label)
},
}}
apiKey={GOOGLE_API_KEY}
autocompletionRequest={{
componentRestrictions: {
// country: [values.group_country && values.group_country.value]
country: ['CA', 'GB', 'US']
},
types:['(cities)']
}}
/>
{meta.error && meta.touched &&
<span className="text-danger small block">{meta.error}</span>}
</div>
)}
</Field>

The answer is really help but I found the input field was empty after I selected the address so I removed one line "value: input.value," it works for me.

Related

How to use Radio button to select a different form in each array of useFieldArray of react-hook-form

I have a basic react hook form with field array. With append the form fields replicates as expected. For each array, I want the user to choose some field to enter without entering the other. I am using radio button and useState to achieve this. However, when i change the selection in an array, the selections in the other arrays changes as well. Please how do i correct this ? Or is there a better way to achieve this functionality. Thanks in advance for your help. The code is found below. I also have codeSandbox: https://codesandbox.io/s/usefieldarray-react-hook-form-2yp3vb?file=/src/App.js:0-3753
export default function App() {
const { handleSubmit, control } = useForm({
defaultValues: {
Detail: [
{
userName: {},
officeAddress: {},
homeAddress: {}
}
]
}
});
const { fields, append, remove } = useFieldArray({
control,
name: "Detail"
});
const [checked, setChecked] = useState();
// onChange function for the address forms
const changeAddressForm = (e) => {
setChecked(e.target.value);
};
const onSubmit = async (data) => {};
return (
<div className="App">
<h1>Selecting a different form in each field array</h1>
<form onSubmit={handleSubmit(onSubmit)}>
<ul>
{fields.map((field, index) => {
return (
<li
key={field.id}
className="w3-border w3-border-green w3-padding"
>
<div>
<div className="w3-padding-large">
<label>Username</label>
<Controller
name={`Detail.${index}.userName`}
control={control}
render={({ field }) => (
<Input
onChange={(value) => field.onChange(value)}
style={{ width: 200 }}
/>
)}
/>
</div>
<div>
<Radio.Group onChange={changeAddressForm} value={checked}>
<Radio value={1}>Office address</Radio>
<Radio value={2}>Home address</Radio>
</Radio.Group>
</div>
<div className="w3-padding-large">
{checked === 1 && (
<div>
<label>Office address</label>
<Controller
name={`Detail.${index}.officeAddress`}
control={control}
render={({ field }) => (
<Input
onChange={(value) => field.onChange(value)}
style={{ width: 200 }}
/>
)}
/>
</div>
)}
</div>
<div className="w3-padding-large">
{checked === 2 && (
<div>
<label>Home address</label>
<Controller
name={`Detail.${index}.homeAddress`}
control={control}
render={({ field }) => (
<Input
onChange={(value) => field.onChange(value)}
style={{ width: 200 }}
/>
)}
/>
</div>
)}
</div>
</div>
</li>
);
})}
</ul>
<section>
<button
type="button"
onClick={() =>
append({
userName: {},
homeAddress: {},
officeAddress: {}
})
}
>
Append
</button>
</section>
</form>
</div>
);
}

How to add error message to yup validation for array containing distinct values in FieldArray?

I am trying to add Error message for my Field Array which should contain array of distinct elements. Below is my validation:
export const emails = yup
.array(
yup
.string()
.matches(/^\S+#\S+$/, {
message: "Must be a valid email id"
})
)
.test("Unique", "Email ids need to be unique", values => {
return new Set(values).size === values.length;
});
And here is the ErrorMessage component inside my FieldArray component's render prop:
render={({ form, push, remove }) => (
<div>
{range(0, form.values[name].length).map(i => (
<div className={styles.inputContainer} key={i}>
<div>
<InputComponent name={`${name}.${i}`} {...props} />
<Button color="danger" onClick={() => remove(i)}>
<FaTimes />
</Button>
</div>
<ErrorMessage
name={`${name}.${i}`}
render={msg => (
<FormFeedback style={{ display: "block" }}>
{msg}
</FormFeedback>
)}
/>
</div>
))}
<Button
color="info"
onClick={() => push("")}
disabled={disabled || form.values[name].slice(-1)[0] === ""}
>
<FaPlus />
</Button>
</div>
)}
However I get the error message as shown below. The message comes as one by one letter. I understand because I am including it in my range render method. But I have included the Error message component inside, because I want to show the error for invalid email ids as well.
I, with help of someone figured out the solution. Let me jot it down if anybody needs it.
Basically, the Error message component prints out any error messages generated. It is not able to distinguish between where and what from the error messages.
So, I made use of of form attribute from render props of FieldArray component. The error message comes as a property of form as form.errors.
However the key to distinguish between the two ErrorMessage components is that the inner form.errors comes as an array and the outer one comes as a string. So the solution is to check the datatype of form.errors object. Below is the code snippet.
render={({ form, push, remove }) => (
<div>
{range(0, form.values[name].length).map(i => {
return (
<div className={styles.inputContainer} key={i}>
<div>
<InputComponent name={`${name}.${i}`} {...props} />
<Button color="danger" onClick={() => remove(i)}>
<FaTimes />
</Button>
</div>
{typeof form.errors[name] !== "string" && (
<ErrorMessage
name={`${name}.${i}`}
render={msg => {
return (
<FormFeedback style={{ display: "block" }}>
{msg}
</FormFeedback>
);
}}
/>
)}
</div>
);
})}
{typeof form.errors[name] === "string" && (
<ErrorMessage
name={`${name}`}
render={msg => (
<FormFeedback style={{ display: "block" }}>
{msg}
</FormFeedback>
)}
/>
)}

google react-places-autocomplete api restrict search suggestions to Australia / single country

Hello I want to limit my search suggestions (and therefore limit a user to choose an Australian address) with react places autocomplete to addresses from Australia, and to note I have checked stack overflow for similar questions and none of them seem to work, here is an example of the suggestions I am currently getting that i would like to be only Australian Suggestions.
screen shot
here is what i think is the relevant code
import PlacesAutocomplete, {
geocodeByAddress,
getLatLng,
} from 'react-places-autocomplete';
<PlacesAutocomplete
fullWidth
className="search-bar"
value={address}
onChange={setAddress}
onSelect={handleSelect}
>
{({ getInputProps, suggestions, getSuggestionItemProps, loading }) => (
<div >
<input
style={{width:"100%" }}
{...getInputProps({
placeholder: 'Enter Job Address',
className: 'location-search-input',
})}
/>
<div className="autocomplete-dropdown-container"
key={suggestions.description}
>
{loading && <div>Loading...</div>}
{suggestions.map((suggestion, index)=> {
const className = suggestion.active
? 'suggestion-item--active'
: 'suggestion-item';
// inline style for demonstration purpose
const style = suggestion.active
? { backgroundColor: '#fafafa', cursor: 'pointer' }
: { backgroundColor: '#ffffff', cursor: 'pointer' };
return (
<div
key={index}
{...getSuggestionItemProps(suggestion, {
className,
style,
})}
>
<span>{suggestion.description }</span>
</div>
);
})}
</div>
</div>
)}
</PlacesAutocomplete>
try with this prop
searchOptions={{componentRestrictions: { country: ['au'] }}}

Ant design <Form.List> create static array of forms

I am using antd with react to develop an application.
<Form.List name="secondaryContacts">
{(fields, { add, remove }) => {
return (
<div>
{fields.map((field, index) => (
<Form.Item
{...formItemLayoutWithOutLabel}
label={index === 0 ? "" : ""}
required={false}
key={field.key}
>
<Form.Item
{...field}
validateTrigger={["onChange", "onBlur"]}
rules={[
{
required: true,
validator: phoneNumberValidator
}
]}
>
<Input
placeholder="Secondary Contact"
addonAfter={
fields.length >= 1 ? (
<MinusCircleOutlined
onClick={() => {
remove(field.name);
}}
/>
) : null
}
/>
</Form.Item>
</Form.Item>
))}
<Form.Item {...formItemLayoutWithOutLabel}>
<Button
type="dashed"
onClick={() => {
add();
}}
style={{ width: "100%" }}
>
<PlusOutlined /> Add Secondary Contact
</Button>
</Form.Item>
</div>
);
}}
</Form.List>;
Above is the code I am using to add dynamic form fields with validation using Form.List.
Now I have a specific scenario where I need to show 7 Sliders(https://ant.design/components/slider/) for the selected time slot and store them in an array, so I thought of using Form.List and keep all sliders inside just like above(except that it's static).
But I am not clear how I can achieve it with Form.List and there are very few examples on the internet.
I have a scenario where I need to have an array of forms and club them as an array using Form.List.
You can use the initialValue property to set the static data
Example:
const staticValue = [{ formItem1: 'value1', formItem2: 'value2'}];
<Form.List name="formListName" initialValue={staticValue}>
{(fields, { add, remove }, { errors }) => (
fields.map((field) => (
<>
<Form.Item {...field} name={[field.name, 'formItem1']}>
<Input placeholder="Field 1" />
</Form.Item>
...
You still need <Form> component
Try
<Form>
<Form.List>
</Form.List>
</Form>

Manage Input inside a List in React

I call a GET from a server and this request return an array of N objects. Then on this array I generate a List using Antd in this way:
render() {
return (
<List
dataSource={this.props.images}
renderItem={image => (
<List.Item actions={
[
<Icon key={"1"+image.Id.toString()} onClick={(e) => this.actionClick('RUN',image.Id, image.RepoTags[0].replace(/[^a-zA-Z0-9]/g,'_'), e)}
className="icon" type="caret-right" />,
<Popconfirm placement="topRight" title="Are you sure delete this image?"
onConfirm={(e) => this.actionClick('REMOVE_IMAGE',image.Id, e)} okText="Yes" cancelText="No">
<Icon key="4" className="icon" type="close" />
</Popconfirm>
]
}>
<List.Item.Meta
title={image.RepoTags[0]}
description={image.Labels ? image.Labels.maintainer : ''}
</List.Item.Meta>
<InputGroup compact className={'inputGroup'}>
<Input style={{ width: '50%' }} placeholder={'inner port'} value={this.state.innerPort} onChange={evt => this.updateValue("innerPort",evt)}/>
<Input style={{ width: '50%' }} placeholder={'redirect'} value={this.state.redirectPort} onChange={evt => this.updateValue("redirectPort",evt)}/>
</InputGroup>
</List.Item>
)}
>
</List>
);
}
As you can see in the code I have an InputGroup for every List.Item and I store the value in the state using:
updateValue(k,v) {
console.log("key", k, "value", v);
console.log(this.state);
this.setState({
[k]:v.target.value
});
}
The problem here is that the I have the same value for every List.Item of the List.
How could I manage this problem with multiple List.Item? I thought of an array, but I didn't make that work.
Change your Input to
<Input style={{ width: '50%' }} placeholder={'inner port'} value={this.state["innerPort"+image.id] } onChange={evt => this.updateValue("innerPort",image.Id,evt)}/>
this will send a unique identifier to the update function and then you can use it like
updateValue(k,id,v) {
console.log("key", k, "value", v);
console.log(this.state);
var myKey=k+id
this.setState({
[myKey]:v.target.value
});
}
Have you tried to use FlatList instead of List, so you can pass the item index to the rendered item.

Resources