How to transform a flat form-specific data-structure into a nested one?

76 Views Asked by At

I have a requirement where one needs to inflate a form-specific flat data-structure. Before sending the user entered values, I need to build a data-structure according to what the server's API does expect.

Say I have following key-value pairs from a user's input

{
  state: "California",
  city: "New York",
  full_name: "rererer",
  email: "[email protected]",
  dob: "1/1/2014",
  pincode: "222222",
  gender: "male",
}

The data API does require a nested object where

  1. an Address will include state, city and full_name
  2. and a Profile has to feature email, dob, pincode and gender.

How does one convert the above key-value pairs into following nested data-structure?

{
  Address: {
    state: "California",
    city: "New York",
    full_name: "rererer",
  },
  Profile: {
    email: "[email protected]",
    dob: "1/1/2014",
    pincode: "222222",
    gender: "male",
  },
}
2

There are 2 best solutions below

1
Sunny On

Simple example is that you can store the json in a variable as X wherein you can create 2 object Address and Profile then put the required fields from the X variable to its respective objects and later merge that object together.

Example:

var jsonObj = {
  state: "California",
  city: "New York",
  full_name: "rererer",
  email: "[email protected]",
  dob: "1/1/2014",
  pincode: "222222",
  gender: "male"
};

var address = new Object();
var profile = new Object();
var combinedObj = new Object();

address.state = jsonObj.state 
address.city = jsonObj.city 
address.full_name = jsonObj.full_name 

profile.email = jsonObj.email
profile.dob = jsonObj.dob
profile.pincode = jsonObj.pincode
profile.gender = jsonObj.gender

combinedObj.Address = address
combinedObj.Profile = profile

console.log(combinedObj);

you can automate this code

0
Peter Seliger On

In short, such an object could be created by destructuring the original data before the final re/assembling takes place where one would utilize the object literal syntax together with e.g. shorthand property names and a template literal ...

const sourceData = {
  state: "California",
  city: "New York",
  full_name: "rererer",
  email: "[email protected]",
  dob: "1/1/2014",
  pincode: "222222",
  gender: "male",
};

// 1) destructuring.
const {
  state, city, full_name, email, dob, pincode, gender
} =
  sourceData;

// 2) re/assembling (object literal syntax).
const targetData = {
  Address: {
    // shorthand property names.
    state, city, full_name,
  },
  Profile: {
    // a template literal and shorthand property names.
    email: `[${ email }](mailto:${ email })`, dob, pincode, gender,
  },
};
console.log({ sourceData, targetData });
.as-console-wrapper { min-height: 100%!important; top: 0; }

A generic approach for this kind of challenge almost always would utilize the FormData Web-API where one would create the raw data-object from the form-data's entries. The finally to be sent payload data then can be assembled easily from the before retrieved and destructured raw data by utilizing the object literal syntax together with e.g. shorthand property names and a template literal ...

function handleProfileAndAddressDataSubmit(evt) {
  evt.preventDefault();

  const { currentTarget: elmForm } = evt;
  const { action: serviceURL, method: apiMethod } = elmForm;

  const formData = new FormData(elmForm);
  const {
    // - destructured and partially renamed
    //   from the before created raw data object.
    state, location: city, full_name,
    email, dob, pincode, gender,
  } =
    // - creating the raw data object
    //   from the form-data's entries.
    Object.fromEntries([...formData.entries()]);

  const payload = {
    // - assambling the final payload object / object literal syntax.
    Address: {
      // shorthand property names.
      state, city, full_name,
    },
    Profile: {    
      // a template literal and shorthand property names.
      email: `[${ email }](mailto:${ email })`, dob, pincode, gender,
    },
  };

  console.log({
    elmForm, formEntries: [...formData.entries()], rawData: {
      email, dob, gender, pincode, full_name, location: city, state,
    },
    payload, apiMethod, serviceURL,
  });
  console.log(
    `Payload data will be send via "${ apiMethod.toUpperCase() }" to "${ serviceURL }"`
  );
}
document
  .forms[0]
  .addEventListener('submit', handleProfileAndAddressDataSubmit);
body { margin: 0; }
fieldset  { margin: 0 4px 8px; padding: 8px; }
fieldset > label, label > span:first-child { display: block; margin: 0 0 4px 0; }
[type="submit"] { margin: 8px 16px; }
form { width: 35% ;}
.as-console-wrapper { left: auto!important; width: 64%; min-height: 100%; }
<form method="post" action="./api/service/path">
  <datalist id="gender-list">
    <option>non binary</option>
    <option>female</option>
    <option>male</option>
  </datalist>

  <datalist id="federal-states">
    <option>Alabama</option>
    <option>California</option>
    <option>Delaware</option>
    <option>Florida</option>
    <option>Georgia</option>
    <option>Hawaii</option>
    <option>Idaho</option>
  </datalist>

  <fieldset>
    <legend>Profile</legend>

    <label>
      <span>Email Address</span>
      <input type="email" required name="email" />
    </label>
    <label>
      <span>Date Of Birth</span>
      <input type="date" required name="dob" />
    </label>
    <label>
      <span>Gender</span>
      <input type="text" list="gender-list" required name="gender" />
    </label>
    <label>
      <span>Pin Code</span>
      <input type="text" inputmode="numeric" pattern="\d{6}" required value="000000" name="pincode" />
    </label>

  </fieldset>

  <fieldset>
    <legend>Address</legend>

    <label>
      <span>Full Name</span>
      <input type="text" required name="full_name" />
    </label>
    <label>
      <span>City / Location</span>
      <input type="text" required name="location" />
    </label>
    <label>
      <span>State</span>
      <input type="text" list="federal-states" required name="state" />
    </label>
  </fieldset>

  <button type="submit">Send</button>
</form>