How can I get an array of strings as the submitted value for react-final-form using react-select? - react-select

I'm trying to get a react-select's multi-select component to submit the selected values as an array of strings but it's coming out as an array of {label, value} objects.
The structure of the objects I will be passing into react-select via react-final-form's Field component is like this:
[
{ val: "first-value", display: "First Value" },
{ val: "second-value", display: "Second Value" },
{val: "third-value", display: "Third Value"
];
Passing the prop getOptionLabel={option => option.display} is able to change the option labels to the display key given by the objects.
However doing the same thing for getOptionValue still gives me the entire {val, display} object when submitted. e.g. selecting the first item and submitting the form would get me [{val: "first-value", display: "First Value" }] when I only want ["first-value"]
I'm not too sure if it's something I need to solve on react-final-form or on react-select
import React from "react";
import { Field } from "react-final-form";
import { Form } from "react-final-form";
import Select from "react-select";
const data = [{ val: "1", display: "123" }, { val: "2", display: "321" }];
const Test2: React.FC<any> = () => {
return (
<Form
onSubmit={values => console.log(values)}
showErrorModal={showErrorModal}
setShowErrorModal={setShowErrorModal}
>
{() => (
<>
<Field
name="test"
component={MultiSelect}
label={"Multi Select test"}
placeholder="Please Select..."
options={data}
getOptionLabel={option => `${option.display}`}
getOptionValue={option => `${option.val}`}
/>
<SubmitButton btnTxt="next" />
</>
)}
</Form>
);
};
export default Test2;
When submitting, the message I get on the console is
[{"val": "1", "display": "123"}, {"val": "2", "display": "321"}]
whereas the result I'm hoping for is
["1","2"]

getOptionLabel & getOptionValue are only for viewing purpose.
When we get the selected value, it will give you the complete object as we provided array of object to options.
So the result of,
onSubmit={values => console.log(values)}
is correct, which is [{"val": "1", "display": "123"}, {"val": "2", "display": "321"}]
You need to further work on this result to get your desired result as,
onSubmit={values => console.log(values.map(data=>data.val))}

Related

Is there any method to implement search input in React Native FlatList?

I want to implement a search bar for flat list data, the problem is that the search function is working but it is not coming back to its original state data after a search is done or search text is null.
const [data,setdata] = useState([{
id: "bd7acbea-c1b1-46c2-aed5-3ad53abb28ba",
fullName: "Bianca Bradley",
timeStamp: "12:47 PM",
recentText: "Contacts",
avatarUrl: "https://images.pexels.com/photos/220453/pexels-photo-220453.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"
}, {
id: "3ac68afc-c605-48d3-a4f8-fbd91aa97f63",
fullName: "Sujitha Mathur",
timeStamp: "11:11 PM",
recentText: "Contacts",
avatarUrl: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTyEaZqT3fHeNrPGcnjLLX1v_W4mvBlgpwxnA&usqp=CAU"
},
]
const handleSearch = text => {
const formattedQuery = text.toLowerCase();
const ndata = data.filter((item) => {
return item.fullName.toLowerCase().match(formattedQuery)
})
setdata(ndata);
setQuery(text);
console.log("Working",ndata)
}
return (
<>
<Center>
<View style={[styles.searchboxview]}>
<Input type="text" value={query} onChangeText={(text)=>handleSearch(text)} style={[styles.searchbox]} textAlign="center" placeholder="Search User Name" w="85%" maxWidth="340px" />
</View>
</Center>
<FlatList data={data} style={[styles.list]} renderItem={({
item
}) keyExtractor={item => item.id} />
</>
)
}
The problem which i can predict is that setdata(ndata) sets to new search data and it doesnot returns back to original data list. What will be the solution for it?
You can add a condition, if the text in textinput is empty then we will set the main data as data which is passed to the flatlist

Implementing react-hook-forms and react-select with radio buttons and multi inputs combo

Ready for a complicated one?
Using react-hook-forms and react-select using creatable (user creates multiple inputs on the fly)
I'm trying to implement a form that uses an option on 4 radio buttons, 2 of which reveal multi inputs (inputs that use react-select where the user can create multiple entries, not a dropdown) and trying to keep track of both the radio inputs and the multi inputs in the final useForm() object. I also need to be able to remove them if the user changes their mind or resets the form in total. Right now, the key values of registrationTypes changes when I change radioTwo and enter inputs. I also don't know how to remove user inputs. I'm using Controller to read the entries (although I've heard if you're using native HTML checkbox input, you have to use Register?) . Here's the code:
import styled from 'styled-components'
import Creatable from 'react-select/creatable'
import { Controller } from 'react-hook-form'
import { ErrorRow } from '../util/FormStyles'
import { FormRulesProps } from '../util/formRuleTypes'
import FormError from './FormError'
const registrationTypes = [
{
label: 'Allow anyone with the link to register',
value: 'radioOne',
},
{
label: 'Allow anyone with this email domain to register:',
value: 'radioTwo',
},
{ label: 'Allow anyone with this code to register:', value: 'radioThree' },
{
label: 'Define eligible users manually through eligibilty file.',
value: 'radioFour',
},
]
const RegistrationEligibilty = () => {
const {
control,
reset,
handleSubmit,
formState: { errors },
} = useForm<any>()
const [selectedRadio, setSelectedRadio] = useState({ regType: '' })
const onSubmit = (data: any) => {
console.log(data)
}
const handleSelected = (value: string) => {
setSelectedRadio({ ...selectedRadio, regType: value })
}
return (
<RegistrationEligibiltyContainer>
<form onSubmit={handleSubmit(onSubmit)}>
<FormRow>
<RadioWrapper>
{registrationTypes.map((rt) => (
<Controller
key={rt.value}
control={control}
name="radio"
render={({ field: { onChange, value } }: any) => (
<RadioGroup
// #ts-ignore
value={value}
onChange={(e: any) =>
onChange(e.target.value, handleSelected(rt.value))
}
>
<Radio
name={rt.value}
type="radio"
value={rt.value}
checked={selectedRadio.regType === rt.value}
/>
<TextRow
text={rt.label}
style={{ paddingLeft: '10px' }}
/>
{selectedRadio.regType === 'radioTwo' &&
rt.value === 'radioTwo' && (
<FormRow>
<div style={{ width: '90%' }}>
<Controller
name={rt.value}
control={control}
render={({ field }) => (
<Creatable
{...field}
isMulti
options={field.value}
value={field.value}
placeholder="Select domains"
/>
)}
/>
</div>
</FormRow>
)}
{selectedRadio.regType === 'radioThree' &&
rt.value === 'radioThree' && (
<FormRow>
<div style={{ width: '90%' }}>
<Controller
name={rt.value}
control={control}
render={({ field }) => (
<Creatable
{...field}
isMulti
options={field.value}
value={field.value}
placeholder="Select codes"
/>
)}
/>
</div>
</FormRow>
)}
</RadioGroup>
)}
/>
))}
</RadioWrapper>
</FormRow>
</FormContent>
</form>
</RegistrationEligibiltyContainer>
)
}
export default RegistrationEligibilty
The result looks like this:
https://imgur.com/a/6oGhqRb
I also need to be able to remove them if the user changes their mind or resets the form in total
If the component is unmounted, the value of the component is not included in the result. Make sure your Creatable is unmounted when the relevant radio is not selected

How do I map an array of key.value to Chip? I have a list of a {k,v} map

Input json for Person - has a xrefAccounts{key,value} map
In the column "SubSys", I want to display "LIBRARY" and "SPORTS" as tags.
The Person json object has all the values required, but I can't figure out how to map it in DataGrid component.
I'm using react-admin 3.10
[{
...
"xrefAccounts": {
"LIBRARY": {
"id": "1",
"xrefSystemId": "LIBRARY"
},
"SPORTS": {
"id": "1",
"xrefSystemId": "SPORTS"
}
}
},
export const PersonList = props => (
<List filters={<PersonFilter />} {...props} >
<Datagrid rowClick="edit">
...
<ReferenceArrayField label="SubSys" reference="id" source="xrefAccounts.value">
{/* Find how to put multiple xref in one column SubSys */}
<SingleFieldList>
<ChipField source="value.xrefSystemId" />
</SingleFieldList>
</ReferenceArrayField>
<EditButton />
</Datagrid>
</List>
);
I want to display SubSys ["Library" "Sports"] similar to Tags["Sport" "Code" ]in this image
It doesn't work because you're using ArrayField on data which is not an array - it is an object!
So the best thing would be actually to fix your API response structure.
But ... if you can't do so - as I look at your attempt maybe I can suggest the following workaround via custom field component:
<XrefAccountsField source="xrefAccounts" />
inside
const XrefAccountsField = ({source, record = {}}) => {
const accountsObject = record[source];
// Convert the record to an array
const accounts = {
accountsArr: accountsObject ? Object.keys(accountsObject).map((key) => accountsObject[key]) : []
};
return (
<ArrayField source="accountsArr" record={accounts}>
<SingleFieldList>
<ChipField source="xrefSystemId" />
</SingleFieldList>
</ArrayField>
)
}

`ArrayInput` but only for a single item

The following snippet inside an Edit context creates an Array as listed below.
import { ArrayInput, SimpleFormIterator, DateInput, TextInput } from 'react-admin';
<ArrayInput source="backlinks">
<SimpleFormIterator>
<DateInput source="date" />
<TextInput source="url" />
</SimpleFormIterator>
</ArrayInput>
JSON:
{
"id": 123,
"backlinks": [
{
"date": "2012-08-10T00:00:00.000Z",
"url": "http://example.com/foo/bar.html",
},
{
"date": "2012-08-14T00:00:00.000Z",
"url": "https://blog.johndoe.com/2012/08/12/foobar.html",
}
]
}
Is there a way to achieve the same for a single item? Something like a reference field but without the feature to select an existing item. Rather the user should need to create one like in the example above.
You don't need a special input component, react-admin inputs let you edit nested objects by default by specifing the path in the source prop
<DateInput source="backlink.date" />
<TextInput source="backlink.url" />
Hope this solves the problem.

React-Native-Material-Dropdown not showing data on Front-end

I have used react-native material dropdown to fetch data from my API as follows:
<Dropdown
label='colors'
data={this.state.data.colors}
containerStyle={{width: 50}}
/>
{console.log("sbHASB",this.state.data.colors)}
However when I implement thi, I do get the colors on my log but they do not seem to appear on the list, it seems to be blank, can anyone please tell me why is ot so?
Any help would be great, thank you.
my logs after implementing are as follows:
sbHASB ["Blue", "White", "Blue", "White", "Blue", "White", "Blue", "White"]
Do tell me if you require anything else.
Assuming you are using react-native-material-dropdown, the documentation on their github suggests that the data prop should be a list of objects with a value key. See here the example given.
import React, { Component } from 'react';
import { Dropdown } from 'react-native-material-dropdown';
class Example extends Component {
render() {
let data = [{
value: 'Banana',
}, {
value: 'Mango',
}, {
value: 'Pear',
}];
return (
<Dropdown
label='Favorite Fruit'
data={data}
/>
);
}
}
For your list to work you should transform it to match this format, for example
const data = this.state.data.colors.map((color) => ({value: color}))
Given your example above that could look like
<Dropdown
label='colors'
data={this.state.data.colors.map((color) => ({value: color}))}
containerStyle={{width: 50}}
/>
However I would advise transforming the data before this step, for example when you receive the response from the api.
see this example on snack.io, the dropdown will work best if you preview it on a device since the animation doesn't display properly on the web preview.
https://snack.expo.io/#dannyhw/dropdown
UPDATE:
Here is the updated example that includes an example of how it can be used dynamically
export default class App extends React.Component {
state = {
data: {colors: []}
}
getSomeData() {
// imagine this is your api call here and it returns a promise that resolves to be a list of colours
return Promise.resolve(["green", "White", "Blue", "White", "Blue", "White", "Blue", "White"])
}
componentDidMount(){
this.getSomeData().then((result)=> {
this.setState(state => state.data.colors = result)
})
}
render() {
return (
<View style={styles.container}>
<Dropdown
label='colors'
data={this.state.data.colors.map((color) => ({value: color}))}
containerStyle={{width: 150}}
/>
</View>
);
}
}