1

How can I convert a string to an object when there is a reference inside the string?

String:

{ "field": "OrderNumber", "operator": "eq", "value" : e.data.OrderNumber }

I already tried with JSON.parse and eval but I'm still getting an error on "e.data.OrderNumber"

2
  • obj.value=e.data.OrderNumber Commented Dec 16, 2016 at 20:32
  • 6
    That is not a valid JSON. e.data.OrderNumber should be treated as a string like this: "e.data.OrderNumber" Commented Dec 16, 2016 at 20:32

5 Answers 5

2

Set "value" to empty string. Call JSON.parse() with str as parameter. Set .value of resulting object.

var str = `{"field":"OrderNumber","operator":"eq","value":""}`;

var obj = JSON.parse(str);

obj.value = e.data.OrderNumber;

An alternative approach would be to utilize JSON.parse() reviver function, with this set to e using Function.prototype.bind(). If key is equal to "value" within the function create a variable val where the value is initially set to undefined. Use .split() to create an array of the property representations within the key "value". .slice() the indexes following 0 from resulting array. Use for..of loop to get the value of obj[arrayIndex] through obj[arrayIndex][propN] where propN is the nth index of array; assign the value to the variable val. Return the variable val following loop, else return value parameter.

var e = {
  data: {
    OrderNumber: 1
  }
};

var str = '{"field":"OrderNumber","operator":"eq","value":e.data.OrderNumber}';

str = str.replace(/((\w+.[\w.]+)(?=(\s+|)\}))/g, "\"$1\"");

var rev = function(key, value) {
  if (key === "value") {
    let [props, val] = [value.split(".").slice(1), void 0];
    for (let prop of props) {
      val = val === undefined ? this[prop] : val[prop];
    }
   return val;
  }
  return value;
};

var obj = JSON.parse(str, rev.bind(e));

console.log(obj);

You can also retrieve and set the value without having the property name using String.prototype.replace() with RegExp /((\w+.[\w.]+)(?=(\s+|)\}))/g to match word character followed by . followed by one of more word characters and . characters; String.prototype.match() to match word characters and create an array from the matches; Array.prototype.reduce() to iterate each depth of object properties for the .length of the array, return the last value at depth of array .length corresponding to object properties within original string.

const e = {
  data: {
    OrderNumber: 1
  }
};

let str = '{ "field": "OrderNumber", "operator": "eq", "value" : e.data.OrderNumber }';

str = str.replace(/((\w+.[\w.]+)(?=(\s+|)\}))/g, function(match) {
  let [,...props] = match.match(/[^.]+/g);
  return props.reduce(function(obj, prop) {
    return obj[prop]
  }, e); 
});

let obj = JSON.parse(str);

console.log(obj);

With resulting array from calls to .match(), .shift(), .split() on original string you can get the property values from e with destructuring assignment; use .replace() to set replacement string with corresponding value from e; then call JSON.parse() with resulting string as value to create a javascript object.

const e = {
  data: {
    OrderNumber: 1
  }
};

let str = '{ "field": "OrderNumber", "operator": "eq", "value" : e.data.OrderNumber }';

let re = /((\w+.[\w.]+)(?=(\s+|)\}))/g;

let obj = JSON.parse(str.replace(re
          , (() => ([,...props] = str.match(re).shift().split(".")
            , {[props[0]]:{[props[1]]:prop}} = e, prop)
            )()
          ));

console.log(obj);

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

2 Comments

If the string is known beforehand, an object initializer could be used instead of a string.
@Oriol Yes, though actual text of Question is "String to Object with refence"
2

Only real option you have to to use eval or new Function since what you have is not valid JSON due to the object property reference. There are security concerns with new Function and eval, so that is why this solution is not the best idea.

var str = '{ "field": "OrderNumber", "operator": "eq", "value" : e.data.OrderNumber }';
var e = { data : { OrderNumber : 123456 } };
var x = new Function("return " + str)();
console.log(x.value);

BUT if I were you, I would see if there is a better way to do what you need instead of using a bandaid to fix the problem. What I would do is have an object and add the property or extend it.

var e = { data : { OrderNumber : 123456 } };
var obj = { "field": "OrderNumber", "operator": "eq" };
obj.value = e.data.OrderNumber;

or

var e = { data : { OrderNumber : 123456 } };
var obj = { "field": "OrderNumber", "operator": "eq" };
var result = {};
Object.assign(result, obj, {value : e.data.OrderNumber} );

5 Comments

Why new Function and not just eval?
@Evert personal preference?
but the data value not will be aways OrderNumber, i will use this string for a filter context: filter: JSON.parse(relationString)
The property does not matter. You can set it to whatever.
But to make the template works I would have to be with the direct string in the code, in my case it comes from the database
1

https://jsfiddle.net/hd3v29ra/2/

You would simply need to adjust the order number to reside within quotations when you insert it into the string to be converted into an object:

example 1 using concatenated strings

var obj = JSON.parse('{"field": "OrderNumber","operator": "eq","value":"' + e.data.orderNumber + '"}');

example 2 using ES6 Template Literals

var obj = JSON.parse(`{"field": "OrderNumber", "operator":"eq","value":"${e.data.orderNumber}"}`);

1 Comment

but the data value not will be aways OrderNumber, i will use this string for a filter context: filter: JSON.parse(relationString)
0

There is the unsafe and evil eval:

var e = {data: {OrderNumber: 123}};
var str = '{ "field": "OrderNumber", "operator": "eq", "value" : e.data.OrderNumber }';
console.log(eval('(' + str + ')'));

Do not use this with untrusted strings, it may run arbitrary code.

1 Comment

but the data value not will be aways OrderNumber, i will use this string for a filter context: filter: JSON.parse(relationString)
0

It's worked with this:

    private static rev(key: any, value: any): any {
        if (key === "value") {
            let [props, val] = [value.split(".").slice(1), void 0];
            for (let prop of props) {
                val = val === undefined ? this[prop] : val[prop];
            }
            return val;
        }
        return value;
    }

And i use JSON.parse(relationString, this.rev.bind(e)) to call the method

1 Comment

The javascript at the current Answer is an exact duplicate of javascript at first stacksnippet at this Answer stackoverflow.com/a/41192130

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.