0

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 [
}}}
0

4 Answers 4

1

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>

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

5 Comments

jsfiddle.net/afnb691k Didn't know how to format my code in comment so I just pasted it in jsfiddle. I didnt implement the whole split search ,but it should work for non-nested properties ,right?
@jsbeginner97 I put a snippet with the exemple in my answer
Just out of curiosity : how would you do the reverse of this thing? populating an object from array with values from input?
jsfiddle.net/o461qnds/6 I managed to come up this, but I couldnt avoid creating a new object.Any idea of how I could modify the initial users array instead?
@jsbeginner97 I added a fiddle on the answer
1

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)
}

Comments

0

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>

Comments

0

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

4 Comments

I think this way is even slower than the first solution he used. Because you call the document.querySelector multiple time, just as he do with his document.getElementById, but the querySelector function has a longer execution than the getElementById
If these aren't the only inputs on my page ,could i try to use const inputs = Array.from(document.getElementByClassName('viewInfo')); instead ?
Oh nevermind,I can use querySelector with a class name as well
If you're targeting more than one element you need querySelectorAll.

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.