Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to initialize an FieldArray? #2366

Closed
zkx34 opened this issue Dec 30, 2016 · 17 comments
Closed

How to initialize an FieldArray? #2366

zkx34 opened this issue Dec 30, 2016 · 17 comments
Labels

Comments

@zkx34
Copy link

zkx34 commented Dec 30, 2016

hi erikras,
i got an sort of datas, array object, but when i try to initialize the FieldArray, i found the FieldArray passed 'fields' props to it's component,and manage the array of fields through 'fields' ,like push() and remove() methods. so i confused, how can i passed my datas to FieldArray and initialize the component , also manage those datas using 'fields' methods(remove() and push()...etc...) ?

@swp44744
Copy link

swp44744 commented Dec 30, 2016

I dint get your question correctly, but see if this is what you are looking for. You can pass your custom array as a prop in FieldArray.

myPersonalArray =['red', 'blue','green']
<FieldArray
name="FieldArrayName"
myPersonalArrayProp={myPersonalArray}
component={this.yourComponentName}
/>

you can access your personal array as below in stateless fun:
yourComponentName= ({fields, myPersonalArrayProp}) => {
console.log('where is my personal array??', myPersonalArrayProp);
}

For push and remove, you need to provide a button in your component function and onClick either push or remove from field like fields.push({}) and fields.remove({index})

hope this helps. for more details refer to the FieldArray example in redux-form documentation

@swp44744
Copy link

swp44744 commented Dec 30, 2016

@gustavohenke @erikras I do have a question though, if I have my custom array and I want to control rendering FieldArray based on length of my custom array instead of having a button to push into fields, how would I do that? I tried to push into fields until the length of my custom array like below but my code went in infinite loop:

yourComponentName= ({fields, myPersonalArrayProp}) => {
myPersonalArrayProp.map((element, index)=>{
fields.push({});
})
}

any thoughts???

@zkx34
Copy link
Author

zkx34 commented Dec 30, 2016

@swp44744 thanks for answer.
I have some thoughts now, i'll try it.

@gustavohenke
Copy link
Collaborator

gustavohenke commented Dec 30, 2016

Hi @swp44744, your code is in infinite loop probably because

  1. React will render your component, and it'll start pushing items into fields
  2. React will see that fields changed somehow, therefore it must be re-rendered!
  3. Go back to step 1

A better idea is to use some lifecycle event like componentWillMount/componentDidMount.

@swp44744
Copy link

swp44744 commented Dec 30, 2016

Thank you Senhor, I will try it. But my custom array list is always going to vary based on user selection in the form which results in custom array. ComponentWillMount will render once.. Will look at other lifecycle events. Appreciate it

@swp44744
Copy link

@gustavohenke I think I can use componentWillReceiveProps but is there a way to access fields outside the FieldArray component??

@erikras
Copy link
Member

erikras commented Dec 30, 2016

is there a way to access fields outside the FieldArray component??

@swp44744
Copy link

Thanks for the response @erikras. I tried doing something like below:

const selector = formValueSelector('formName');

function mapStateToProps(state) {
let fieldArrayObject = selector(state,'fieldArrayName');

return {
fieldArrayObject
}
}

But as FieldArray's fields does not have any element in it. formValueSelector returns undefined. I can initialize the fieldArray with an empty object to begin with, but for some reasons I didn't wanted to do that, as I want to render FieldArray exact times as my custom array length. let me try though.

@swp44744
Copy link

swp44744 commented Jan 3, 2017

This question can be closed!!!

@erikras erikras closed this as completed Jan 3, 2017
@rodpatulski
Copy link

@swp44744 Did you ever figure this out?

@RayFinney
Copy link

@swp44744 Yeah i wonder too, running at the same issue while init a select in FieldArray

@rodpatulski
Copy link

@Tiega91 I figured out the problem in my case. It was because I was using fields.map (also known as fields.forEeach) thinking I was actually using the plain old javascript map function but I was in fact using this http://redux-form.com/7.0.4/docs/api/FieldArray.md/#iteration

I first had to use fields.getAll() to receive a regular array and then loop through it normally. In essence, if you're trying to just render your fields, it seems to me like fields.map is an easy way of doing that, but if you're trying to loop through your values to do something other than render the s in your , then make sure to use fields.getAll()

@RayFinney
Copy link

RayFinney commented Sep 8, 2017

@rodpatulski Holy Moly

fields.map (also known as fields.forEeach) thinking I was actually using the plain old javascript map function but I was in fact using this http://redux-form.com/7.0.4/docs/api/FieldArray.md/#iteration

haha, this should be a big warning somewhere it was also my mistake. Now i have the issue that the "input.name" is not set correct. because i used

name={${com}.CategoryID}

That only works with the fields.map iterator. Do i have to create the input name manually?

###########
Did it as follow:
<Field component="input" className="form-control" name={fields.name+"["+index+"].Value"} />

@swp44744
Copy link

swp44744 commented Sep 8, 2017

Sorry for late reply... glad it worked for you.. let me know if you still have issues I will try to help.

@rodpatulski
Copy link

@Tiega91

Did it as follow:
<Field component="input" className="form-control" name={fields.name+"["+index+"].Value"} />

I found that all I had to do was

<FieldArray name={${curInventory}.nightlyInventoryAmt} component={renderAmounts} key={index} containerName={${curInventory}.containerName}/>

{fields.map((curAmount, index) => <td key={index}> <Field component={SimpleField} name={curAmount} type="number"/> </td> )}

within my fields.map iterator as you said, the output of which was ''. I have run into trouble before trying to mimick the naming structure of what a outputs without actually using a as a side note.

@sasajib
Copy link

sasajib commented Sep 20, 2017

For those who are searching for solution to add/remove fields dynamically with props/data, I was able to do. There could be better ways...

My use case is, when user select countries, it should load players with some form fields.
SampleData

components

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class ArrayContainer extends Component {

    constructor(props, context) {
        super(props, context);
    }

    indexData(data) {
        return data.map((d, index) => {
            return { ...d, ...{ index } };
        });
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.data !== this.props.data) {
            const { fields, compareKey } = this.props;
            const dataWithIndex = this.indexData(nextProps.data);

            if (fields.length < dataWithIndex.length) {
                dataWithIndex.forEach((d, i) => {
                    try {
                        if (fields.get(i)[compareKey] !== d[compareKey]) {
                            fields.insert(i, d);
                        }
                    } catch (error) {
                        fields.insert(i, d);
                    }
                });
            } else if (fields.length > dataWithIndex.length) {
                fields.getAll().forEach((f, i) => {
                    fields.remove(fields.length - 1);
                    const data = dataWithIndex[i];
                    if (data === undefined) fields.remove(i);
                    else {
                        if (f[compareKey] !== data[compareKey]) {
                            fields.insert(i, data);
                        }
                    }
                });
            } else {
                if (fields.length) {
                    fields.getAll().forEach((f, i) => {
                        const data = dataWithIndex[i];
                        if (f[compareKey] !== data[compareKey]) {
                            fields.insert(i, data);
                        }
                    });
                }
            }
        }

    }
}

ArrayContainer.propTypes = {
    data: PropTypes.array.isRequired,
    compareKey: PropTypes.string.isRequired
};

export default ArrayContainer;

import React from 'react';
import { connect } from 'react-redux';
import ArrayContainer from './ArrayContainer';
import { Field } from 'redux-form';

class TeamFormContainer extends ArrayContainer {

    constructor(props, context) {
        super(props, context);
    }

    render() {
        //your form Field/s component here
        const inputFields = this.props.fields.map((field, index) => {
            return (
                <div key={index}>
                    {JSON.stringify(this.props.fields.get(index))}
                </div>
            );
        });
        return (
            <div>
                {inputFields}
            </div>
        );
    }

}

function mapStateToProps(state) {
    return {
        teams: state.teamPlayers
    };
}

TeamFormContainer = connect(mapStateToProps)(TeamFormContainer);

export default TeamFormContainer;

usage

<FieldArray
        name="teams"
        component={TeamFormContainer}
        props={{data: selectedTeams, compareKey: 'id'}}
/>

hope it helps others, thx

@lock
Copy link

lock bot commented Sep 22, 2018

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Sep 22, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

7 participants