Wolden
Wolden

Reputation: 333

javascript serialize json array with commas

I'm trying to apply this function How parameterize array to as single comma separated value? in a 'function called by its name' script but it doesn't work as expected:

function add(a,b,c){
    return a+b+c
}

var vals = callFct("add", window, 2,3,4); 
document.getElementById('result').innerHTML += "<br>Function result: "+vals
// result = Function result: 9 ----> 2+3+4 : OK

The values are coming from: json={a:[2,3,4]}

function serialize(vals){
    var output = [];
    for (var prop in vals) {
        if (vals.hasOwnProperty(prop)){
            output.push(vals[prop].join(','));
        }
    }
    return output;
}

var json = {a:[2,3,4]};
document.getElementById('result').innerHTML += "<br>Used data:  "+serialize(json)
// result = Used data: 2,3,4 ---> seems to be OK... but

var test = callFct("add", window, serialize(json)); 
document.getElementById('result').innerHTML += "<br>Function result:  "+test
// result = Function result : 2,3,4undefinedundefined ---> oups

I've tried to remove the 'undefined' ...

document.getElementById('result').innerHTML += "<br>Function result :  "+test.replace(/undefined/g,'')
// result = Function result : 2,3,4 ---> nope

The called function:

function callFct(w, y, z ) {  
  var z = Array.prototype.slice.call(arguments, 2);
  console.log('vars = '+z)
  let v = w.split(".");
  let x = v.pop();
  for(var i = 0; i < v.length; i++) {
    y = y[v[i]];
  }
  return y[x].apply(y, z);
}

What's wrong in my way to proceed?

Upvotes: 0

Views: 535

Answers (2)

Wolden
Wolden

Reputation: 333

Finally found a simpliest solution:

// define empty vars
let a, b, c;    
const vars = [a, b, c];

// call function by its name
function callFct(fct) {  
  const toks = fct.split(".");
  const last = toks.pop();
  for(var i = 0; i < toks.length; i++) {
    window = window[toks[i]];
  }
  return window[last].apply(window, vars); // vars now in array
}

// functions to be called
function add(){
   return a+b+c
}
function substract(){
   return a-b-c
}  
function multiply(){
   return a*b*c
}

// produce real vars values
a = 20, b = 10, c = 5;

// get results
var add = callFct("add");
console.log(add); // 20+10+5 = 35

c = -5 // actualize any value
var subs = callFct("substract");
console.log(subs); // 20-10--5 = 15

var mult = callFct("multiply");
console.log(mult); // -1000

// mixing functions results
function mix(){
    return add/subs
}
var mixed = callFct("mix");
console.log(mixed); // 2.3333333333333335

Upvotes: 0

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48600

Please provide better parameter names than w, y, and z...

If you change the names to the one's seen in the demo below, your return statement will look like the following:

return scope[last].apply(funcName, serialized);

If you notice, you are calling apply on window.add. Make sure that method exists. I am not sure what add looks like, but it will take the "serialized" JSON data and the scope of the call will be the incoming string (first) parameter (which can apparently be dot-separated).

Notes

  1. You can change this: [...output, json[prop].join(',')] to this: output.concat(json[prop].join(',')) for browser compatability.
  2. A "basic" polyfill for flatMap can be found here: https://stackoverflow.com/a/39838385/1762224

const json = { a: [2, 3, 4] };

document.getElementById('result-1').innerHTML = 'Values: ' + serialize(json);

let sum = callFct('add', window, serialize(json));
document.getElementById('result-2').innerHTML = 'Sum: ' + sum;

let difference = callFct('subtract', window, serialize(json));
document.getElementById('result-3').innerHTML = 'Difference: ' + difference;

function serialize(json) {
  return Object.keys(json).reduce((output, prop) => {
    return [...output, json[prop].join(',')];
  }, []);
}

function callFct(funcName, scope, serialized) {
  serialized = Array.from(arguments).slice(2);
  console.log('vars = ' + serialized)
  const tokens = funcName.split('.');
  const last = tokens.pop();
  for (let i = 0; i < tokens.length; i++) {
    scope = scope[tokens[i]];
  }
  return scope[last].apply(funcName, serialized);
}

function prepareValues(serialized) {
  return serialized
    .flatMap(v => v.split(/,\s*/g))
    .map(v => parseInt(v, 10));
}

function add(serialized) {
  return prepareValues(serialized)
    .reduce((s, v) => s + v, 0);
}

function subtract(serialized) {
  return prepareValues(serialized)
    .reduce((s, v) => s - v);
}
div[id^="result-"] { font-family: monospace; }
<script src="https://polyfill.io/v3/polyfill.min.js?features=Array.prototype.flatMap"></script>
<div id="result-1"></div>
<div id="result-2"></div>
<div id="result-3"></div>

Upvotes: 1

Related Questions