0

I need to be able to combine this into one function. There are 2 separate arrays...

{this.state.telephoneType.map((telephoneType, ttidx) => ())}

and...

{this.state.telephone.map((telephone, tidx) => ())}

Basically, this is because I have a button which concatenates the 2 functions and it has to be outside the row class (MDBRow) so the UI doesn't break.

<MDBRow className="grey-text no-gutters my-2">

    {this.state.telephoneType.map((telephoneType, ttidx) => (

        <MDBCol md="4" className="mr-2">
            <select
                key={ttidx}
                defaultValue={telephoneType.name}
                onChange={this.handleTelephoneTypeChange(ttidx)}
                className="browser-default custom-select">
                <option value="Mobile">Mobile</option>
                <option value="Landline">Landline</option>
                <option value="Work">Work</option>
            </select>
        </MDBCol>
    ))}

    {this.state.telephone.map((telephone, tidx) => (

        <MDBCol md="7" className="d-flex align-items-center">
            <input
                value={telephone.name}
                onChange={this.handleTelephoneChange(tidx)}
                placeholder={`Telephone No. #${tidx + 1}`}
                className="form-control"
            />
            <MDBIcon icon="minus-circle"
                className="mr-0 ml-2 red-text"
                onClick={this.handleRemoveTelephone(tidx)} />
        </MDBCol>

    ))}

</MDBRow>

<div className="btn-add" onClick={this.handleAddTelephone}>
    <MDBIcon className="mr-1" icon="plus-square" />
        Add Telephone
</div>

This is the handleAddTelephone function...

handleAddTelephone = () => {
    this.setState({
        telephone: this.state.telephone.concat([{ name: "" }]),
        telephoneType: this.state.telephoneType.concat([{ name: "" }])
    });

};

and the Constructor looks like this...

class InstallerAdd extends React.Component {
    constructor() {
        super();
        this.state = {
            role: "Installer",
            name: "",
            telephoneType: [{ name: "" }],
            telephone: [{ name: "" }],
            tidx: "",
            emailType: [{ email: "" }],
            email: [{ email: "" }],
            eidx: "",
            notes: ""
        };
    }
}

Can I nest one array inside the other? I'm not sure how to do this so any advice appreciated. Thanks.

Edit: These are the 2 telephone functions which need to be 1 function... I have updated with new nested array for each

handleTelephoneChange = tidx => evt => {
    const newTelephone = this.state.telephone.type.map((telephone, tsidx) => {

        if (tidx !== tsidx) return telephone;
        return { ...telephone, name: evt.target.value };
    });
    this.setState({ telephone: newTelephone }, () => {
        // get state on callback
        console.log(this.state.telephone.number[tidx].name)
    }
    );
};

handleTelephoneTypeChange = ttidx => evt => {
    const newTelephoneType = this.state.telephone.number.map((telephoneType, ttsidx) => {
        if (ttidx !== ttsidx) return telephoneType;
        return { ...telephoneType, name: evt.target.value };
    });
    this.setState({ telephoneType: newTelephoneType }, () => {
        // get state on callback
        console.log(this.state.telephone.type[ttidx].name)
    }
    );
};

My constructor now looks like this...

class InstallerAdd extends React.Component {
    constructor() {
        super();
        this.state = {
            role: "Installer",
            name: "",
            telephone: {
                type: [{ name: "" }],
                number: [{ name: "" }]
              },
            tidx: "",
            emailType: [{ email: "" }],
            email: [{ email: "" }],
            eidx: "",
            notes: ""
        };
    }
6
  • Will be easier to understand if you show what single array you expect from 2 examples arrays Commented Jun 28, 2019 at 13:34
  • Are you wanting a single array as such: telephone: [{ type: "...", phone: "..."}, ...]? I don't see anything that wrong with what you have to be honest. What are you trying to accomplish? Commented Jun 28, 2019 at 13:50
  • You can see here it breaks the UI because the function needs to be wrapped around the Row class. This isnt possible with 2 functions. screencast.com/t/HksUkk7g3G I will try what has been suggested. Thanks. Commented Jun 28, 2019 at 14:04
  • I guess it isn't clear how the UI breaks, and it still isn't clear what you are asking for or what your expected result should be. It's starting to sound now like you want just a single handler to handle both update cases. Commented Jun 28, 2019 at 15:14
  • @DrewReese I have come back to this and yes you are correct I need a single handler so when I call the handleAddTelephone function I can call 'telephone' rather than telephoneType and telephone. Please see my screencast video which shows what happens when I call handleAddTelephone screencast.com/t/HksUkk7g3G Commented Jul 17, 2019 at 9:29

2 Answers 2

0

Although I still don't quite understand how your UI "breaks" (video won't load for me), I hope I can help. Basically the short answer about trying to map two arrays singly is that you can't (well, shouldn't), but with some assumptions about the two array's length always being equal and the order is the same between the two, then you can map over the first array and use the passed index from the map function to access the second.

arrayA.map((itemFromA, index) => {
  // do stuff with item from A
  const itemFromB = arrayB[index];
  // do stuff with item from B
});

I think the better solution is to keep only a single array in state to map over in the first place.

state = {
  telephones: [], // { type: string, number: string }[]
}
...
state.telephones.map(({ type, number }, index) => {
  // do stuff with telephone type
  ...
  // do stuff with telephone number
});

If you also really want only a single change handler (I recommend they be separate), you can adopt a redux action/reducer type handler that accepts an object as a parameter that has all the data you need to update an array entry (index, update type, value). Here's a pretty clean example, but requires a bit of "action" setup when called:

changeHandler = (index, type) => e => {
  const newTelephoneData = [...this.state.telephones];
  newTelephoneData[index][type] = e.target.value;
  this.setState({ telephones: newTelephoneData });
}

<select
  value={type}
  onChange={this.telephoneChangeHandler(index, "type")}
>
  // options
</select>

...

<input
  value={number}
  onChange={this.telephoneChangeHandler(index, "number")}
  placeholder={`Telephone No. #${index + 1}`}
/>

Below I've created a few working sandbox demos:

  • Dual telephone data arrays, single change ("action/reducer") handler, separate add/remove functions, single map pass using index accessor to second array: Edit nested-dual-array-update
  • Single telephone data array, single change handler, separate add/remove, single map pass: Edit nested-single-array-update
  • Use react useReducer, single array, reducer handles add/remove/update, single map pass: Edit nested-single-array-update-hooks

I've included code documentation but if anything is unclear please let me know and I can clean up these demos.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for taking the time to reply. I did come up with a solution although some of your code looks cleaner, particularly the select options. I will take a proper look tomorrow. The solution I used is on this post stackoverflow.com/questions/56805133/…
0

Yes, absolutely, something along:

telephone: {
  list: [1,2,3],
  type: [“foo”, “bar”, “baz”]
}

1 Comment

Thanks for that. I have updated my original post with this now and updated the 2 telephone functions. How would I create 1 map function rather than 2? This short video should help explain what Im trying to achieve and how the UI breaks. screencast.com/t/qg8ccYPmrKJ1

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.