22

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']
6
  • Have you tried it and gotten an error? Commented Jul 22, 2018 at 21:08
  • 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"/> Commented Jul 22, 2018 at 22:42
  • 1
    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. Commented Jul 23, 2018 at 10:37
  • 2
    @yBrodsky 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! Commented Jul 25, 2018 at 10:31
  • 2
    @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 data Commented Jul 25, 2018 at 13:18

5 Answers 5

14

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>
Sign up to request clarification or add additional context in comments.

6 Comments

I have tried to use this solution, but getting error like 'Failed prop type: Invalid prop value supplied to TextField.'
@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"
@AswathyBalan @Hola Use empy string for source <TextInput source="" />
Worth noting this fails for the ArrayField, but works for ArrayInput for some reason
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.
|
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>

2 Comments

Seems like this should also work as <TextArrayField source="tags" /> as the custom component isn't using the children passed to it.
If you are struggling with nested values, replace the record[source] with this: ` import get from 'lodash/get'; ... const array = get(record, source); ... `
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>

Comments

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

Comments

0

This is how I did to get it work:

        <ArrayInput source="backlinks">
          <SimpleFormIterator inline>
            <TextInput source="." />
          </SimpleFormIterator>
        </ArrayInput>

1 Comment

Is this formally supported by react-admin?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.