How can I get react-select to integrate properly with react-final-form - react-select

I'm using react-final-form to send along some basic user data. First name, last name, email and a dropdown value with a reason why they're contacting me. I tried the following (the custom input section on react-final-form's docs):
<Field name="myField">
{props => (
<div>
<Select
options={colourOptions}
className="basic-multi-select"
classNamePrefix="select"
onChange={props.input.onChange}
/>
</div>
)}
</Field>
My guess is maybe there's some collision with the onChange prop? Not sure, but the information in the dropdown is not being picked up by react-final-form and pass along to the <form> on submit.

There is an example on how to use react-select with react-final-form: https://codesandbox.io/s/40mr0v2r87.
You should add an adapter:
const ReactSelectAdapter = ({ input, ...rest }) => (
<Select {...input} {...rest} />
)
And then you can use it as a component:
<Field
name="state"
component={ReactSelectAdapter}
options={states}
/>

Here my approach. I decided problem with initial values and value which will sent to server. Just like:
{selectFieldId: "value"}
import React from "react";
import { FieldRenderProps } from "react-final-form";
import Select, { ValueType } from "react-select";
type Option = {
label: string;
value: string;
};
export const CustomSelect = ({ input, options, ...rest }: FieldRenderProps<string, HTMLElement>) => {
const handleChange = (option: ValueType<Option, false>) => {
input.onChange(option?.value);
};
return (
<Select
{...input}
{...rest}
onChange={handleChange}
options={options}
value={options ? options.find((option: Option) => option.value === input.value) : ""}
/>
);
};
export default CustomSelect;

in a simple way I have done it like this:
const locationOptions = [
{ value: 1, label: "ADEN" },
{ value: 2, label: "MUKALLA" },
{ value: 3, label: "TAIZ" },
];
<Field name="location_id">
{({ input }) => (
<Select
options={locationOptions}
placeholder="Select Location"
{...input}
/>
)}
</Field>
the on submit method:
const onSubmit = (data) => {
console.log(data);
};

Related

React-native form validation with react-hook-form and Yup

I try to validate a form in React-Native (0.69.6) with react-hook-form (7.29.0) and yup (0.32.11 with #hookform/resolvers 2.9.10).
I have this minimal reproducible example that always show isValid as false and errors as an empty object {}:
const schema = yup
.object()
.shape({
name: yup.string().required(),
})
.required();
const {
control,
formState: { errors, isValid },
} = useForm({
resolver: yupResolver(schema),
});
return (
<>
<Text>{JSON.stringify(errors)}</Text>
<Text>{JSON.stringify(isValid)}</Text>
<Controller
control={control}
render={({ field: { onChange, value } }) => (
<Input value={value} onChangeText={onChange} />
)}
name="name"
/>
</>
);
Why this simple validation does not work, what am I missing?
errors and isValid are populated when submitting the form.
In order to see them updated in live as the data changes, just add:
mode: "onChange",
as follow:
const {
control,
handleSubmit,
formState: { errors, isValid },
} = useForm({
mode: "onChange",
resolver: yupResolver(schema),
});

Autocompletearrayinput TypeError: Polyglot.transformPhrase expects argument #1 to be string

Hello stack overflow I was wondering if its possible to pre-populate with default values upon rendering. I'm also getting an error when using the from react admin. Here's my how i'm using my .
return (
<Edit {...props}>
<SimpleForm>
<TextInput source="audience_name" />
<ReferenceInput label="entity_ids" source="entity_ids" reference="posts">
<EntityInput setEntityLabel={onChangeLabel} onSelectEntity={addEntity} entityNames={entityNames} />
</ReferenceInput>
<br />
<AutocompleteArrayInput
source="tags"
shouldRenderSuggestions={(val) => {
console.log(val);
return val.trim().length > 0;
}}
choices={[
{ id: 'programming', name: 'Programming' },
{ id: 'lifestyle', name: 'Lifestyle' },
{ id: 'photography', name: 'Photography' },
]}
/>
</SimpleForm>
</Edit>
);
};
Try to add the props translateChoice={false}, like:
<AutocompleteInput source="first_name" choices={choices} translateChoice={false}/>
You can try recreating the i18nProvider, like this:
import polyglotI18nProvider from "ra-i18n-polyglot"; // Install this package
import engMessages from "ra-language-english"; // Install this package
const App = () => {
const i18nProvider = polyglotI18nProvider((locale) => engMessages, "en", {
allowMissing: true,
onMissingKey: (key, _, __) => key,
});
return (
<Admin
...
i18nProvider={i18nProvider}
>
)
}

Use the Datagrid component with custom queries - react-admin

Receive below errors, when using Datagrid component with custom queries. Below code works with react-admin ver 3.3.1, whereas it doesn't work with ver 3.8.1
TypeError: Cannot read property 'includes' of undefined
Browser's console info: List components must be used inside a <ListContext.Provider>. Relying on props rather than context to get List data and callbacks is deprecated and won't be supported in the next major version of react-admin.
Refer: https://marmelab.com/react-admin/List.html
#Tip: You can use the Datagrid component with custom queries:
import keyBy from 'lodash/keyBy'
import { useQuery, Datagrid, TextField, Pagination, Loading } from 'react-admin'
const CustomList = () => {
const [page, setPage] = useState(1);
const perPage = 50;
const { data, total, loading, error } = useQuery({
type: 'GET_LIST',
resource: 'posts',
payload: {
pagination: { page, perPage },
sort: { field: 'id', order: 'ASC' },
filter: {},
}
});
if (loading) {
return <Loading />
}
if (error) {
return <p>ERROR: {error}</p>
}
return (
<>
<Datagrid
data={keyBy(data, 'id')}
ids={data.map(({ id }) => id)}
currentSort={{ field: 'id', order: 'ASC' }}
basePath="/posts" // required only if you set use "rowClick"
rowClick="edit"
>
<TextField source="id" />
<TextField source="name" />
</Datagrid>
<Pagination
page={page}
perPage={perPage}
setPage={setPage}
total={total}
/>
</>
)
} ```
Please help!
Since react-admin 3.7, <Datagrid> and <Pagination> read data from a ListContext, instead of expecting the data to be injected by props. See for instance the updated <Datagrid> docs at https://marmelab.com/react-admin/List.html#the-datagrid-component.
Your code will work if you wrap it in a <ListContextProvider>:
import React, { useState } from 'react';
import keyBy from 'lodash/keyBy'
import { useQuery, Datagrid, TextField, Pagination, Loading, ListContextProvider } from 'react-admin'
export const CustomList = () => {
const [page, setPage] = useState(1);
const perPage = 50;
const { data, total, loading, error } = useQuery({
type: 'GET_LIST',
resource: 'posts',
payload: {
pagination: { page, perPage },
sort: { field: 'id', order: 'ASC' },
filter: {},
}
});
if (loading) {
return <Loading />
}
if (error) {
return <p>ERROR: {error}</p>
}
return (
<ListContextProvider value={{
data: keyBy(data, 'id'),
ids: data.map(({ id }) => id),
total,
page,
perPage,
setPage,
currentSort: { field: 'id', order: 'ASC' },
basePath: "/posts",
resource: 'posts',
selectedIds: []
}}>
<Datagrid rowClick="edit">
<TextField source="id" />
<TextField source="name" />
</Datagrid>
<Pagination />
</ListContextProvider >
)
}
<ReferenceManyField>, as well as other relationship-related components, also implement a ListContext. That means you can use a <Datagrid> of a <Pagination> inside this component.
https://marmelab.com/react-admin/List.html#uselistcontext
Your code should look like this:
import React, { useState } from 'react';
import keyBy from 'lodash/keyBy'
import { useQuery, Datagrid, TextField, Pagination, Loading, ListContextProvider } from 'react-admin'
export const CustomList = () => {
return (
<ReferenceManyField reference="Your resource for pull the data" target="linked field">
<Datagrid rowClick="edit">
<TextField source="id" />
<TextField source="name" />
</Datagrid>
</ReferenceManyField>
)
}

DatePicker input value not pass to Redux Form when submit

I'm using DatePicker with ReduxForm. However, when I click submit button, the input value from Date Picker not pass to Redux Form.
I've search around and come across the answer from this (my code of renderDatePicker comes from there) but it still doesn't work for me.
My demo of the form on my Simulator:
Here's my code:
import React, { Component } from 'react';
import {
View, Text, Button, Icon, Container, Item,
Input, Label, Content, Form, Picker, Footer, DatePicker
} from 'native-base';
import { Field, reduxForm } from 'redux-form';
import { addTransactionItem } from '../redux/ActionCreators';
import moment from 'moment';
import { connect } from 'react-redux';
const mapDispatchToProps = dispatch => ({
addTransactionItem: (transactionItem) => dispatch(addTransactionItem(transactionItem))
})
class AddTransaction extends Component {
constructor(props) {
super(props);
this.renderField = this.renderField.bind(this);
this.submit = this.submit.bind(this);
this.renderDatePicker = this.renderDatePicker.bind(this);
}
renderDatePicker = ({ input, placeholder, defaultValue, meta: { touched, error }, label ,...custom }) => (
<Item>
<Label>{label}</Label>
<DatePicker {...input} {...custom} dateForm="MM/DD/YYYY"
onChange={(value) => input.onChange(value)}
autoOk={true}
selected={input.value ? moment(input.value) : null} />
{touched && error && <span>{error}</span>}
</Item>
);
submit = values => {
alert(`The values are ${JSON.stringify(values)}`)
const transactionItem = JSON.parse(JSON.stringify(values))
this.props.addTransactionItem(transactionItem);
const { navigate } = this.props.navigation;
navigate('Home');
}
render() {
const { handleSubmit } = this.props
return (
<>
<Form>
<Field keyboardType='default' label='Date' component={this.renderDatePicker} name="date" />
</Form>
<Button full light onPress={handleSubmit(this.submit)}>
<Text>Submit</Text>
</Button>
</>
);
}
}
AddTransaction = connect(null, mapDispatchToProps)(AddTransaction);
export default reduxForm({
form: 'addTransaction',
})(AddTransaction);
I think this is because you do not have "change" attribute in the Field component.
Try to add change function as shown below:
renderDatePicker = (
{
input,
placeholder,
defaultValue,
meta: { touched, error },
label ,
...custom,
change
}
) => (
<Item>
<Label>{label}</Label>
<DatePicker {...input} {...custom} dateForm="MM/DD/YYYY"
onDateChange={change}
autoOk={true}
selected={input.value ? moment(input.value) : null} />
{touched && error && <span>{error}</span>}
</Item>
);
render() {
const { handleSubmit, change } = this.props
return (
<>
<Form>
<Field
keyboardType='default'
label='Date'
component={this.renderDatePicker}
name="date"
change={change}
/>
</Form>
<Button full light onPress={handleSubmit(this.submit)}>
<Text>Submit</Text>
</Button>
</>
);
}
Hope it will work for you.
I see that there is no onChange listener for DatePicker. May be you should use onDateChange. http://docs.nativebase.io/Components.html#picker-input-headref

Redux-Form: Selecting form values from array of objects

I'm trying to select form values from array and show them below the input section. I know how to do it with individual fields but arrays are confusing me.
Here I am rendering array of fields:
export const renderAddressFields = ({ fields, meta: { touched, error } }) => (
<View>
{touched && error && <Text style={styles.ErrorMessage} >{error}</Text>}
{fields.map((ad, index) =>
<View key={index}>
<Text>Address #{index + 1}</Text>
<View style={styles.AddressFields}>
<Field
name={`${ad}.StreetName`}
type="default"
component={renderField}
label="Street Name"/>
<Field
name={`${ad}.Number`}
type="numeric"
component={renderField}
label="Street Number"/>
</View>
</View>
)}
</View>
)
And here is my (unsuccessful) attempt to select individual values from array of fields:
const { handleSubmit, mySubmit, fullAddress} = this.props
...
<Text>{fullAddress}</Text>
...
Form = reduxForm({
form: 'registerForm', // a unique identifier for this form
validate,
})(withRouter(Form))
const selector = formValueSelector('registerForm') // <-- same as form name
Form = connect(
state => {
const { StreetName, Number } = selector(state, { Addresses: [{ StreetName: 'StreetName', Number: 'Number' }] })
return {
fullAddress: `${StreetName || ''} ${ Number || ''}`
}
}
)(Form)
export default Form
your selector looks like a problem source.
do it something like this :
renderAddressFields = connect(state => {
let nameValue = selector(state, "nameofyourfieldarray[0].StreetName");
return {
nameValue
};
})(renderAddressFields)
then use it like:
export const renderAddressFields = ({ fields, meta: { touched, error }, nameValue })