1

I have a form with dynamic fields. I want to format some serialized data before submit. I need to reproduce the PHP $$var in Javascript.

Here is the idea in PHP :

I have this :

$data = array('field1', 0, 'key');
$val = 'somevalue';

And I want this :

$field1[0]['key'] = 'somevalue';

So, here is how I would proceed if I were in PHP (I'm not sure if it would work) :

$data = array('field1', 0, 'key');
$val = 'somevalue';

$field1 = array();
$f = $data[0];           # 'field1'
$i = $data[1];           # 0
$k = $data[2];           # 'key'
$$f[$i][$k] = $val;      # $field1[0]['key'] = 'somevalue';

I saw that we can use window[var] in JS but I don't manage to make it work, I tried this :

var val = 'somevalue';
var field1 = [];
var f = data[0];
var i = data[1];
var k = data[2];

window[f][i] = {};           # field1[0] must be an object
window[f][i][k] = val;       # field1[0] = {'key': 'somevalue'}

As you can see, it's not very simple. Besides, this code is within a foreach because I don't have only one field but a lot of (field2, field3...).

At the end, I have something like :

var result = {
  field1: field1,
  field2: field2,
  ...
  field10: field10
}

// console.log(result);
{
  field1: [
    0 : Object { key: 'somevalue', key2: 'othervalue' }
    ...
    5 : Object { key: 'somevalue2', key2: 'othervalue2' }
  ]
  field2: [...]
  ...
}

EDIT:

Thanks to the answer of @Nina Scholz:

function formatData(object, keys, value) {
    var last = keys.pop();

    keys.reduce((o, k, i, a) =>
        o[k] = o[k] || (isFinite(i + 1 in a ? a[i + 1] : last) ? [] : {}),
        object
    )[last] = value;

    return object;
}

var data = form.serializeArray();
var result = {};

$(data).each(function(i) {
    name = data[i].name;        // field name. Ex: "field1[0][key]"
    value = data[i].value;      // field value

    // Format: "field1[0][key]" => array("field1", "0", "key")
    array = name.split('[');
    array[1] = array[1].replace(']', '');
    array[2] = array[2].replace(']', '');

    // Format every array of data in a big object "result"
    formatData(result, array, value);
});

// JSON encoding of "result" in a hidden field for post-treatment
$('input[name=data]').val(JSON.stringify(result));
Eve
  • 776
  • 2
  • 11
  • 32
  • there is no. but you could use either `eval`, which is not advisable or an object where you collect all wanted data and access by a key. – Nina Scholz Oct 31 '18 at 15:28
  • maybe it is easier to add the form (a small one) and what you like to serialize of it. – Nina Scholz Oct 31 '18 at 15:31
  • @NinaScholz `data` is already the result of `form.serializeArray()`, I did a foreach on it to format some data in it. – Eve Oct 31 '18 at 15:33
  • @rpaskett Please, read my entire post before answering. I already tested your solution. – Eve Oct 31 '18 at 15:37
  • Possible duplicate of [How to use a variable for a key in a JavaScript object literal?](https://stackoverflow.com/questions/2274242/how-to-use-a-variable-for-a-key-in-a-javascript-object-literal) – dossy Oct 31 '18 at 16:12
  • See also: [Creating object with dynamic keys](https://stackoverflow.com/a/19837961/512686) – dossy Oct 31 '18 at 16:13

3 Answers3

1

You could take the object directly and take a path to the value for setting. This approach checks the key, if that is a number for an array as default value. If an array or object is given, it does not change the data structure.

function setValue(object, keys, value) {
    var last = keys.pop();

    keys.reduce((o, k, i, a) =>
        o[k] = o[k] || (isFinite(i + 1 in a ? a[i + 1] : last) ? [] : {}),
        object
    )[last] = value;

    return object;
}

var val = 'somevalue',
    data = ['field1', 0, 'key'],
    result = {};

setValue(result, data, val);
console.log(result);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Woah thank you very much @Nina ! It's exactly what I wanted to do, works perfectly. – Eve Nov 05 '18 at 07:50
-1

You shouldn't create variables dynamically.

let o = {};
o[f][i][k] = val;

writing o.field is not much different from writing just field

To answer your question, you cannot do that in javascript like you can in php. For the record, that counts as poor code also in PHP. In the case of PHP, it prevents the compiler from applying all optimizations.

The function scope is different from the global scope.

This writes the variable bar in the global scope, not in a local scope

var bar = 123; // global bar

(() => {
    var bar; // local bar

    window["bar"] = 456; // this is writing in global "bar", not the local one
})();

console.log(bar);
  • I tried `eval()` too but I don't manage to make it work, could you write me an example that corresponds to my example ahead, please ? – Eve Oct 31 '18 at 15:39
  • Sorry, this answer is wrong. As of ES2015/ES6, you can use a variable as a key in an object literal. – dossy Oct 31 '18 at 16:15
  • and how is that related to what the user was asking? the function scope is not accessible as variable like `window` is – ChunkyBarsEater Oct 31 '18 at 16:23
  • you cannot create a variable with a dynamic name. the only way is eval eval("let " + name + " = " + whatever_serializer(value)); – ChunkyBarsEater Oct 31 '18 at 16:26
-2

If you have an array of variable names and you want to create an object where the keys are the variable names and the values are the variable values, this is an example of how you can do that:

var fields = [ 'field1', 'field2', 'field3', 'field4'];

var field1 = 'foo';
var field2 = 'bar';
var field3 = 'baz';
var field4 = 'quux';

var obj = {};

for (var i = 0; i < fields.length; i++) {
    obj[fields[i]] = eval(fields[i]);
}

console.log(obj);

/*
{
  "field1": "foo",
  "field2": "bar",
  "field3": "baz",
  "field4": "quux"
}
*/
dossy
  • 1,617
  • 16
  • 26