4

I'm trying to create a JavaScript function that creates an object using strings for structure and fills it from DOM data.

For example, the following strings could look like this:

some.example.here = "hello"
some.example.there = "hi"
other.example = "heyo"

Which should create this object:

{
    some: {
        example: {
            here: "hello",
            there: "hi"
        },
    other: {
        example: "heyo
    }
}

The data as said comes from DOM and is being load at the code segment labeled "read data into object". The data loads fine and the object structure is being setup fine as well, but the data is not being put into the data field.

Here's the code for the function:

function getDataFromElement(element) {
  obj = {};
  $(element)
    .find("[data-value]")
    .each(function() {
      // create object node
      valueObj = {};
      currentValueObj = valueObj;
      $.each($(this).attr("data-value").split("."), function(i, objpath) {
        currentValueObj[objpath] = {};
        currentValueObj = currentValueObj[objpath];
      });

      // read data into object
      if($(this).is("[data-putvalue]") && $(this).attr("data-putvalue") != "html") {
        currentValueObj = $(this).attr($(this).attr("data-putvalue"));
      } else {
        currentValueObj = $(this).html();
      }

      console.log(currentValueObj);

      // combine with previous gathered data
      obj = $.extend(true, {}, obj, valueObj);
    });

  return obj;
}

Does anyone know what to do?

Addison
  • 7,322
  • 2
  • 39
  • 55
Lukas Bach
  • 3,559
  • 2
  • 27
  • 31
  • Can include `html` at Question? , create stacksnippets , jsfiddle http://jsfiddle.net to demonstrate ? – guest271314 Aug 15 '15 at 21:32
  • What is purpose of `currentValueObj = currentValueObj[objpath];` ? – guest271314 Aug 15 '15 at 21:38
  • With the second each loop I'm trying to create the object structure, so the loop goes through each element of the string, creates a new subelement with the current string-element-name with `currentValueObj[objpath] = {};` and goes into that subelement with `currentValueObj = currentValueObj[objpath];`, so that in the next loop-walk the next subelement will be created there. – Lukas Bach Aug 15 '15 at 21:46
  • `currentValueObj` appear overwritten at each iteration ? Can include `html` at Question , create stacksnippets to demonstrate ? – guest271314 Aug 15 '15 at 21:51

4 Answers4

4

I would do it like this:

var createObject = function(model, name, value) {
  var nameParts = name.split("."),
  currentObject = model;
  for (var i in nameParts) {
    var part = nameParts[i];
    if (i == nameParts.length-1) {
      currentObject[part] = value;
      break;
    }
    if (typeof currentObject[part] == "undefined") {
      currentObject[part] = {};
    }
    currentObject = currentObject[part];
  }
};

And then use it like that:

var model = {};
createObject(model, "some.example.here", "hello");
createObject(model, "some.example.there", "hi");
createObject(model, "other.example", "heyo");
Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
2

Probably this can suit you (adapted from another project of mine, adapt and use as needed): NOTE the element's name is taken as key and value as the value

function fields2model( $elements, dataModel )
{
    $elements.each(function( ){
        var $el = $(this), 
            name = $el.attr('name'), 
            key, k, i, o, val
        ;

        key = name;

        val = $el.val() || '';

        k = key.split('.'); o = dataModel;
        while ( k.length )
        {
            i = k.shift( );
            if ( k.length ) 
            {
                if ( !o.hasOwnProperty( i ) ) o[ i ] = /^\d+$/.test( k[0] ) ? [ ] : { };
                o = o[ i ];
            }
            else 
            {
                o[ i ] = val;
            }
        }
    });
}

Example use:

<input name="some.example.here" value="hello" />
<input name="some.example.there" value="hi" />


var model = {};
fields2model($('input,textarea,select'), model);

The example elements above will give the below model:

model = {
some: {
    example: {
        here: "hello",
        there: "hi"
    }
};
Nikos M.
  • 8,033
  • 4
  • 36
  • 43
  • 1
    I tried your function here: https://plnkr.co/edit/NhsnQJs1iYWKUCff2aVU?p=preview but it did not work - probably my mistake. Can you help, please? – ESP32 Jul 28 '16 at 10:09
  • I got it working: https://plnkr.co/edit/EyGmop9CmYO3WAf9odvU Javascript is strange - isn't it? ;-) – ESP32 Jul 28 '16 at 10:40
2

Some functional implementation:

const value = 'hello';
'some.example.here'.split('.').reverse().reduce((reduction, segment, index) => {
  const result = {};
  if (index === 0) {                                                                 
    result[segment] = value;
  } else {                                                               
    result[segment] = reduction;
  }

  return result;
}, {})
theFreedomBanana
  • 2,462
  • 2
  • 22
  • 29
1

@theFreedomBanana +1

Works for me

const magicFunction = (string, value) =>
  string
    .split('.')
    .reverse()
    .reduce((acc, cur, index) => ({ [cur]: index === 0 ? value : acc }), {});
  • Please don't add "thank you" as an answer. Instead, just vote up the answers that you find helpful. - [From Review](/review/late-answers/30348256) – tdy Nov 16 '21 at 03:43