React-admin Array input with array of strings/numbers
Asked Answered
V

5

21

https://marmelab.com/react-admin/Inputs.html#arrayinput Examples cover cases where you have an array of objects:

  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 it possible to have it work with just an array of strings?

backlinks: ['a', 'b', 'c']
Vet answered 22/7, 2018 at 20:23 Comment(6)
Have you tried it and gotten an error?Egeria
Yes. The thing is that I don't know what to put in the inner fields in the "source" attribute. With an object its <TextField source="url"/>Vet
You may need to create an alternative ArrayInput. Start with a copy and make modifications. Have a good look at the source. github.com/marmelab/react-admin/blob/master/packages/… Also notice the fact that redux' FieldArray is used.Tace
alright, will have a look that wayVet
@Vet have you come up with something? Do you mind sharing? I am looking for the exact same thing, I have a simple flat array of emails (strings) that I want to be able to nicely edit, add or remove. Cheers!Pomelo
@VojtaHejda nah, I failed miserably. Tried to create my own component (with blackjack and hookers) using redux-form, but couldn't do it. Don't have much experience with the whole react thing. So I ended up using marmelab.com/react-admin/Inputs.html#referencearrayinput Works fine and does what I intended with the bonus that it shows you the related model dataVet
B
13

I was able to execute the inputs variant, as opposed to the fields variant, by simply not providing a source attribute for the inner TextField, and sourcing the array in the actual ArrayField. Then of course just use a SimpleFormIterator. Clearly React favors the use of keys, treating array types like maps, for the most part.

<ArrayInput source="my-source">
  <SimpleFormIterator>
    <TextInput />
  </SimpleFormIterator>
</ArrayInput>
Bickerstaff answered 28/10, 2018 at 12:46 Comment(6)
I have tried to use this solution, but getting error like 'Failed prop type: Invalid prop value supplied to TextField.'Touchandgo
@Aswathy - did you solve it? I get another error: Error: Cannot set a numeric property on an object though my array contains URLs such as "picsum.photos/800"Botello
@AswathyBalan @Botello Use empy string for source <TextInput source="" />Applecart
Worth noting this fails for the ArrayField, but works for ArrayInput for some reasonChickadee
This solutiton worked for react-admin 3.17.2 - I just had to add a key to TextInput otherwise only the first element would render. A simple key={Math.random()} did the job.Bicipital
It's important to note that with empty source you will not be able to add a new element if element prior is falsey (example 0 for number input, or empty string for text input)Koressa
D
4

Here is my working code based on @fzaninotto's post in react-admin Issues:

import Chip from '@material-ui/core/Chip'

const TextArrayField = ({ record, source }) => {
  const array = record[source]
  if (typeof array === 'undefined' || array === null || array.length === 0) {
    return <div/>
  } else {
    return (
      <>
        {array.map(item => <Chip label={item} key={item}/>)}
      </>
    )    
  }
}
TextArrayField.defaultProps = { addLabel: true }

Usage:

  <TextArrayField source="tags">
    <SingleFieldList>
      <ChipField source="id" />
    </SingleFieldList>
  </TextArrayField>
Dregs answered 23/10, 2019 at 7:4 Comment(2)
Seems like this should also work as <TextArrayField source="tags" /> as the custom component isn't using the children passed to it.Francois
If you are struggling with nested values, replace the record[source] with this: ` import get from 'lodash/get'; ... const array = get(record, source); ... `Handicapper
H
1

Maybe you can create your own Field component which can able to take source and record as props.

 function populateList(numbers) {
        return numbers.map((number) =>
            <li key={number.toString()}>
                {number}
            </li>
        );
    }

    const SimpleArray = ({source, record = {}}) =>
        <ul>
            {
                populateList(record[source])
            }
        </ul>;


    SimpleArray.defaultProps = {
        addLabel: true,
        label: 'List'
     };


    SimpleArray.propTypes = {
        label: PropTypes.string,
        record: PropTypes.object,
        source: PropTypes.string
    };

    export default SimpleArray;

And easily use it inside any form element like :

  <SimpleShowLayout>
                        <TextField source="id"/>
                        <TextField label="Title" source="title" className={classes.name}/> 
                        <TextField source="title"/>
                        <NumberField source="defaultItemCount"/>
                        <RichTextField source="description"/>
                        <NumberField source="priceInNumber"/>
                        <SimpleArray source="attributeArray" label="Product Attributes" />




                    </SimpleShowLayout>
Headwards answered 12/12, 2018 at 13:48 Comment(0)
Z
0

My solution expands a bit on the answer from @kcrawford

In my case, I needed to output the array of URLs. Simplified version of the code

const MassMessageEdit: FC<any> = (props) => (
  <Edit {...props}>
    <SimpleForm {...props}>
      ...
      <ArrayField source="onesignalUrls">
        <URLs />
      </ArrayField>
    </CreateEditForm>
  </Edit>
)

const URLs: React.FC<{ ids?: string[] }> = (props) => {
  if (!props["ids"]) return null
  return (
    <ul>
      {props["ids"].map((link, key) => (
        <li key={key}>
          <a href={JSON.parse(link) as string} rel="noopener noreferrer" target="_blank">
            Notification {key + 1}
          </a>
        </li>
      ))}
    </ul>
  )
}

ArrayField passes the values array as ids, which can later be parsed and rendered

Zingg answered 28/7, 2022 at 17:52 Comment(0)
K
0

This is how I did to get it work:

        <ArrayInput source="backlinks">
          <SimpleFormIterator inline>
            <TextInput source="." />
          </SimpleFormIterator>
        </ArrayInput>
Koziel answered 2/3, 2023 at 13:55 Comment(1)
Is this formally supported by react-admin?Copse

© 2022 - 2024 — McMap. All rights reserved.