Asking
Asking

Reputation: 4192

Save values in array of data

My react application take data from user and should output them when user click on SUBMIT button. Now user open the application appears a number input. There he can set a number, for example 2. After that appears 2 boxes, where user can add fields cliking on the button +. In each field user have to add his name and last name. Now the application works, but no in the right way.
Now, if user add his user name and last name in first box and click on SUBMIT, everithing appears in:

 const onFinish = values => {
    const res = {
      data: [dataAll]
    };
    console.log("Received values of form:", res);
  };

But if user add one another inputs clicking on add fields button, the first data dissapears. The same issue is when user add data in 2 boxes, the data is saved just from the last box.

function handleInputChange(value) {
    const newArray = Array.from({ length: value }, (_, index) => index + 1);
    setNr(newArray);
  }

  const onFinish = values => {
    const res = {
      data: [dataAll]
    };
    console.log("Received values of form:", res);
  };

  return (
    <div>
      <Form name="outter" onFinish={onFinish}>
        {nr.map(i => (
          <div>
            <p key={i}>{i}</p>
            <Child setDataAll={setDataAll} nr={i} />
          </div>
        ))}
        <Form.Item
          name={["user", "nr"]}
          label="Nr"
          rules={[{ type: "number", min: 0, max: 7 }]}
        >
          <InputNumber onChange={handleInputChange} />
        </Form.Item>
        <Form.Item>
          <Button htmlType="submit" type="primary">
            Submit
          </Button>
        </Form.Item>
      </Form>
    </div>
  );
};

Mu expected result after clicking on submit is:

data:[
       {
  nr:1,
  user: [
      {
      firstName:'John',
      lastName: 'Doe'
      },
      {
      firstName:'Bill',
      lastName: 'White'
      }
       ]
       },
              {
  nr:2,
  user: [
      {
      firstName:'Carl',
      lastName: 'Doe'
      },
      {
      firstName:'Mike',
      lastName: 'Green'
      },
      {
      firstName:'Sarah',
      lastName: 'Doe'     
      }
       ]
       }, 
     ]
   ....  
     // object depend by how many fields user added in each nr

Question: How to achieve the above result?
demo: https://codesandbox.io/s/wandering-wind-3xgm7?file=/src/Main.js:288-1158

Upvotes: 0

Views: 235

Answers (1)

J&#243;zef Podlecki
J&#243;zef Podlecki

Reputation: 11283

Here's an example how you could do it.

As you can see Child became Presentational Component and only shows data.

Rest of logic went to the Parent component.

const { useState, useEffect, Fragment } = React;

const Child = ({nr, user, onAddField, onChange}) => {

  return <div>
    <div>{nr}</div>
    {user.map(({firstName, lastName}, index) => <div key={index}>
    <input onChange={({target: {name, value}}) => onChange(nr, index, name, value)} value={firstName} name="firstName" type="text"/>
    <input onChange={({target: {name, value}}) => onChange(nr, index, name, value)} value={lastName} name="lastName" type="text"/>
    </div>)}
    <button onClick={() => onAddField(nr)}>Add Field</button>
  </div>
}

const App = () => {
  const [items, setItems] = useState([
  {
    nr: 1,
    user: []
  },
  {
    nr: 2,
    user: [
      {firstName: 'test1', lastName: 'test1'},
      {firstName: 'test2', lastName: 'test2'}
    ]
  }
  ]);  

  const onCountChange = ({target: {value}}) => {
    
    setItems(items => {
      const computedList = Array(Number(value)).fill(0).map((pr, index) => ({
        nr: index + 1,
        user: []
      }))
      
      const merged = computedList.reduce((acc, value) => {
        const item = items.find(pr => pr.nr === value.nr) || value;
        
        acc = [...acc, item];
        
        return acc;
      }, [])
      
      return merged;
    })
    
  }

  const onChildChange = (nr, index, name, value) => {
    setItems(items => {
      const newItems = [...items];
      const item = newItems.find(pr => pr.nr === nr);
      const field = item.user.find((pr, ind) => index === ind)
      field[name] = value;
      
      return newItems;
    });
  }
  
  const onAddField = (nr) => {
    setItems(items => {

      const newItems = [...items];
      const item = newItems.find(pr => pr.nr === nr);
      item.user = [...item.user, {
        firstName: '',
        lastName: ''
      }];

      return newItems;
    })
  }

  const onClick = () => {
    console.log({data: items});
  }

  return <div>
    {items.map((pr, index) => <Child {...pr} onAddField={onAddField} onChange={onChildChange} key={index} />)}
    <input onChange={onCountChange} value={items.length} type="number"/>
    <button onClick={onClick}>Submit</button>
  </div>
}

ReactDOM.render(
    <App />,
    document.getElementById('root')
  );
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<div id="root"></div>

Upvotes: 1

Related Questions