jsbeginner97
jsbeginner97

Reputation: 3

How to populate multiple input fields from an array of objects

What Am I trying to achieve: -less DOM calls in viewData function and overall a cleaner aproach to it.

My code and what I've done so far:

function viewData(){
var uid=document.getElementById("viewUserId").value;
for(i in users){
  if(users[i].id==uid){
   document.getElementById("nameEditInput").value=users[i].name;
   document.getElementById("userNameEditInput").value=users[i].username;
   document.getElementById("emailEditInput").value=users[i].email;
   document.getElementById("streetEditInput").value=users[i].address.street;
   document.getElementById("suiteEditInput").value=users[i].address.suite;
   document.getElementById("cityEditInput").value=users[i].address.city;
   document.getElementById("zipEditInput").value=users[i].address.zipcode;
   document.getElementById("latEditInput").value=users[i].address.geo.lat;
   document.getElementById("lngEditInput").value=users[i].address.geo.lng;
}
}

My idea :

I thought of giving my inputs a common class instead of an ID (for example "viewInfo") and create an array that stores my inputs. After that,I could parse through that array and assign my object values to my class input array.The problem I encountered with this was that I didn't know how to parse through my object.

var x = document.getElementsByClassName('viewInfo');
for(i in users){
 if(users[i].id==uid){
    for(k in x){
       x[k].value=users[k].[i]; //this gives me an error :Unexpected token [
}}}

Upvotes: 0

Views: 1770

Answers (4)

ggirodda
ggirodda

Reputation: 780

You have to give to your inputs a name field, wich will be the equivalent attribute in user object

var inputs = document.getElementsByClassName('viewInfo');
const user = users.find(u => { return u.id === uid })
if (user) {
  Object.keys(inputs).forEach(i => {
    let inputName = inputs[i].getAttribute('name')
    inputs[i].value = user[inputName]
  })
}

For nested properties in user object, you can use an attribute name like this
<input name="address.geo.lat" value="74023">
and then use the split and a recursive function to get the nested value of the object

const users = [
  {
    id: 1,
    name: 'Bob',
    username: 'bob01',
    email: '[email protected]',
    address: {
      street: 'Letsby Avenue',
      suite: '999',
      city: 'London',
      zipcode: 90210
    }
  },
  {
    id: 2,
    name: 'Bob2',
    username: 'bob02',
    email: '[email protected]',
    address: {
      street: 'Letsby Avenue',
      suite: '999',
      city: 'London',
      zipcode: 90210
    }
  }
]

function getNestedValue(obj, keys) {
  let key = keys.shift()
  if (keys.length) {
    return getNestedValue(obj[key], keys)
  }
  return obj[key]
}

function viewData(){
  var uid=document.getElementById("viewUserId").value;
  var inputs = document.getElementsByClassName('viewInfo');
  const user = users.find(u => { return u.id === parseInt(uid) })
  if (user) {
    Object.keys(inputs).forEach(i => {
      let inputName = inputs[i].getAttribute('name');
      inputs[i].value = getNestedValue(user, inputName.split('.'))
    })
  }
}
viewData()
<html>
  <body>
    <form>
      <input type="hidden" id="viewUserId" value="2">
      <input class="viewInfo" name="name">
      <input class="viewInfo" name="username">
      <input class="viewInfo" name="email">
      <input class="viewInfo" name="address.street">
      <input class="viewInfo" name="address.suite">
      <input class="viewInfo" name="address.city">
      <input class="viewInfo" name="address.zipcode">
    </form>
  </body>
</html>

Here you can find the reversed function

const users = [
  {
    id: 1,
    name: 'Bob',
    username: 'bob01',
    email: '[email protected]',
    address: {
      street: 'Letsby Avenue',
      suite: '999',
      city: 'London',
      zipcode: 90210
    }
  },
  {
    id: 2,
    name: 'Bob2',
    username: 'bob02',
    email: '[email protected]',
    address: {
      street: 'Letsby Avenue',
      suite: '999',
      city: 'London',
      zipcode: 90210
    }
  }
]

function generateNestedValue(obj, keys, value) {
  let key = keys.shift()
  if (keys.length) {
    obj[key] = obj[key] || {}
    generateNestedValue(obj[key], keys,  value)
    return
  }
  obj[key] = value
}

function generateUser(){
  var inputs = document.getElementsByClassName('viewInfo');
  let user = {}
  Object.keys(inputs).forEach(i => {
    let inputName = inputs[i].getAttribute('name');
    generateNestedValue(user, inputName.split('.'), inputs[i].value)
  })
  console.log(user)
}
generateUser()
<html>
  <body>
    <form>
      <input class="viewInfo" name="id" value="2">
      <input class="viewInfo" name="name" value="Bob">
      <input class="viewInfo" name="username" value="bob01">
      <input class="viewInfo" name="email" value="[email protected]">
      <input class="viewInfo" name="address.street" value="Via Ciro Fanigliulo">
      <input class="viewInfo" name="address.suite" value="4">
      <input class="viewInfo" name="address.city" value="Grottaglie">
      <input class="viewInfo" name="address.zipcode" value="74023">
    </form>
  </body>
</html>

Upvotes: 1

Andy
Andy

Reputation: 63524

How about storing the values in an object. Each property key would would have an input in the HTML with a corresponding name. You can then iterate over the keys/values and add the value to the input with that key.

const obj = {
  name: 'Bob',
  username: 'bob01',
  email: '[email protected]',
  address: {
    street: 'Letsby Avenue',
    suite: '999',
    city: 'London',
    zipcode: 90210
  }
};

// Cache the inputs
const inputs = Array.from(document.querySelectorAll('input'));

function addProps(inputs, obj) {

  // Loop over the object entries (k = key, v = value)
  for (let [k, v] of Object.entries(obj)) {

    // If the current property is another object
    // (in this case `address`) call the function again
    // with that object
    if (typeof obj[k] === 'object') {
      addProps(inputs, obj[k]);
    } else {

      // Find the input where the name matches the key
      // and set its value
      inputs.find(input => {
        return input.getAttribute('name') === k;
      }).value = v;
    }
    
  }
}

// Call the function passing in the inputs and data object
addProps(inputs, obj);
<input name="name" />
<input name="username" />
<input name="email" />
<input name="street" />
<input name="suite" />
<input name="city" />
<input name="zipcode" />

Documentation

Upvotes: 0

Sebastian Scholl
Sebastian Scholl

Reputation: 1095

You could achieve this with only 1 (or 2...) DOM calls if you're willing to create the input fields with scripting.

let uuid = document.getElementById('viewUserId').value
let user = users.find(user => user.id == uuid)

if (user) {
  let form = document.createElement('form')

  Object.keys(user).forEach(key => {
    let input = document.createElement('input')

    input.setAttribute(key, user[key])
    input.setAttribute('name', key)

    form.appendChild(input)
  })

  document.append(form)
}

Upvotes: 1

danh
danh

Reputation: 62686

First, I'd get the user lookup out of the loop. Then, document.querySelectorAll() will get all the elements of a class. Since the html element ids match the user properties, a little string manipulation on the id will let you set the value of the correct property in a single statement...

let users = [{
    id: 5,
    name: "Peter",
    email: "[email protected]"
  },
  {
    id: 6,
    name: "Paul",
    email: "[email protected]"
  },
  {
    id: 7,
    name: "Mary",
    email: "[email protected]"
  }
];

function clicked() {
  let uid = parseInt(document.getElementById("userId").value);
  let user = users.find(u => u.id === uid);  // lookup the user
  if (!user) {
    alert(`No such uid ${uid}`);
    return;
  }

  document.querySelectorAll('.myClass').forEach(function(el) {
    let elementId = el.id;
    let propName = elementId.replace('EditInput', '');  // the id has a suffix
    el.value = user[propName];  // set the value from the user

  });
}
Enter a user id (5, 6 or 7 are valid) <input id="userId"></input>
<button onClick="clicked()">Go</button><br/><br/>
<input class="myClass" id="nameEditInput"></input>
<input class="myClass" id="emailEditInput"></input>

Upvotes: 0

Related Questions