`ArrayInput` but only for a single item - react-admin

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.

Related

How to set color of asterisk added by FieldTitle component for validation={required()} fields

There seems to be no way of styling the asterisk that FieldTitle adds for components that have validation={required()} fields.
You can use an asterisk that mui provides for required fields by providing the "required" attribute, but you'll get just two asterisks.
React-admin v2
No, react-admin provides no API to style the asterisk in its Input components.
You'll have to build your own Input component, as explained in the react-admin documentation:
import TextField from '#material-ui/core/TextField';
import { useInput, required } from 'react-admin';
const BoundedTextField = props => {
const {
input: { name, onChange, ...rest },
meta: { touched, error },
isRequired
} = useInput(props);
return (
<TextField
name={name}
label={props.label}
onChange={onChange}
error={!!(touched && error)}
helperText={touched && error}
required={isRequired}
{...rest}
/>
);
};
If you’re using FormLabel from Material-UI and you have to use it for selected fields, you can use with required and MuiFormLabel-asterisk.
<FormLabel required sx={{ '& .MuiFormLabel-asterisk': { color: '#FF0000' } }}>Title</FormLabel>

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

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

How can I get an array of strings as the submitted value for react-final-form using 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))}

How to Delete html tags form responseJson in react native?

How can I delete html tags? I need to show description, but html tag not support in react native.
json:
[
{
"id": 73,
"name": "Hello World",
"status": "publish",
"description": "<p>hello</p>\n",
...
codes:
componentDidMount(){
return fetch('example.com/testttttttttttttttttttttttttttttttttt')
.then((response)=>response.json()).
then((responseJson)=>{
let ds = new ListView.DataSource({rowHasChanged:(r1,r2)=>r1!=r2});
this.setState({
isLoading:false,
dataSource:ds.cloneWithRows(responseJson)
});
}).catch((error)=>console.error(error));
}
and listView:
<ListView
dataSource={this.state.dataSource}
renderRow={ (rowData)=>
<View style={{width:'100%',height:40}}>
<View style={{marginTop:5,marginBottom:5}}>
<Text>{rowData.name}</Text>
<Text>{rowData.description}</Text>
</View>
</View>
}
/>
Stripping html tags is not a trivial problem. Many issues have been discussed in the question Strip HTML from Text JavaScript.
In my opinion, the best approach would be to use a library like striptags. Then your code would look like:
<Text>{striptags(rowData.description)}</Text>
Another, more naive implementation could use String.prototype.replace:
<Text>{rowData.description.replace(/<(?:.|\n)*?>/gm, '')}</Text>