Eliya Cohen
Eliya Cohen

Reputation: 11488

parse from string as object path

Let's say I have a form, and I want to check what inputs has been declared in the form, so I do something like this:

let inputs = {};

['first_name', 'last_name', ...].forEach(name => {
    let input = document.querySelector(`input[name="${name}"]`);

    if (input !== undefined)
        inputs = Object.assign(inputs, {[input.getAttribute('name')]: input.value});
}

In this case, so far so good.

But what if have some inputs called ['name.first', 'name.last']? then, it will store the data to an object like this:

{name.first: '...', name.last: '...'}.

and not like this: (which is my desired result)

{
    name: {
        first: '...',
        last: '...'
    }
}

How can I tell JavaScript to parse it as an object path instead of a key string?

Upvotes: 0

Views: 485

Answers (3)

Xotic750
Xotic750

Reputation: 23482

Using the same principle as the other answers (split, test and create) for creating paths, but demonstrates an alternative of your filtering example (as mentioned in my comment).

const wanted = ['name.first', 'name.second', 'name.last'];
const result = Array.from(document.querySelectorAll('input'))
  .filter(input => wanted.includes(input.name))
  .reduce((a, input) => {
    const paths = input.name.split('.');
    const key = paths.pop();
    let current = a;
    paths.forEach(path => current = current[path] ?
      current[path] :
      current[path] = Object.create(null));
    current[key] = input.value;
    return a;
  }, Object.create(null));

console.log(result);
<input name="name.first" value="Eliya" />
<input name="name.middle" value="Wibble" />
<input name="name.last" value="Cohen" />

Upvotes: 0

Amit
Amit

Reputation: 6304

I would use a custom assigning function.

An object can use any string as key, so "a.b" is valid.

Here is an example of an assign function:

function assign(obj, key, value) {
    let keys = key.split(".");
    let last = keys.pop();
    keys.forEach(key => {
        if(!obj[key])
            obj[key] = {};
        obj = obj[key];
    });

    obj[last] = value;
}

let obj = {};
assign(obj, "name.first", "hey");
assign(obj, "name.last", "bye");

console.log(obj);

Bonus recomendation: you can use it as a global form handler, if you use the same format to all forms.

function formHandler(form) {
    let obj = {};
    form.querySelectorAll("input, select").forEach(elem => assign(obj, elem.name, elem.value));
    return obj;
}

Upvotes: 1

IAmDranged
IAmDranged

Reputation: 3020

Something like that?

  var obj = {
      'prop': 'value',
      'nested.prop1': 'value1',
      'nested.prop2': 'value2',
      'renested.prop1': 'value1',
      'renested.prop2': 'value2',    
      'nested.prop3': 'value3',
  }

  function deconcatProp(obj){

      var idx;
      var key;

      for(var prop in obj){
          if((idx = prop.indexOf('.')) > 0){
              key = prop.substring(0, idx);
              if(!obj[key]) {
                  obj[key] = {
                  };
              }
              obj[key][prop.substring(idx + 1, prop.length)] = obj[prop];
              delete obj[prop];
          }
      }

  }

 deconcatProp(obj);

Upvotes: 0

Related Questions