1

I need to build an object string by string, and then use eval() to create the object.

I was successful doing this with an array of objects, but the next part, an object, is not working.

These three jsFiddles show the progression:

Chart with normal array (pieData) and object (pieOptions)

Chart with array formed of strings - works

Add object formed of strings - no work


There is considerable discussion about why I use eval(). The array and object used for data and options respectively are both formed bit-by-bit as strings, and then glomped together into an array and an object. This jsFiddle will demonstrate a (simpler) version of my problem:

http://jsfiddle.net/81fpdc44/3/

Please show me how to make s1...s5 into an array without using eval(). Am I missing something (not an uncommon situation...) ?


For Posterity: The code

Working (array):

<canvas id="pieChart" height="400" width="300"></canvas>

pieD  = '{value:25, color:"red"},';
pieD += '{value:5, color:"blue"},';
pieD += '{value:25, color:"palegreen"},';
pieD += '{value:10, color:"darkcyan"},';
pieD += '{value:35, color:"wheat"}';
eval('pieData = ['+pieD+']');

var pieOptions = {
    annotateDisplay : true,
    segmentShowStroke : false,
    segmentStrokeColor : "white",
    segmentStrokeWidth : 1,
    percentageInnerCutout : 0,
    animation: false,
    animationSteps : 100,
    animationEasing : "easeOutQuart",
    animateRotate : true,
    animateScale : false,
    legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"
};


var ctx = document.getElementById("pieChart").getContext("2d");
var myPieChart = new Chart(ctx).Pie(pieData,pieOptions);

Not working:

pieO  = 'annotateDisplay : true,';
pieO += 'segmentShowStroke : false,';
pieO += 'segmentStrokeColor : "white",';
pieO += 'segmentStrokeWidth : 1,';
pieO += 'percentageInnerCutout : 0,';
pieO += 'animation: false,';
pieO += 'animationSteps : 100,';
pieO += 'animationEasing : "easeOutQuart",';
pieO += 'animateRotate : true,';
pieO += 'animateScale : false,';
pieO += 'legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"';
eval('pieOptions = {'+pieO+'}');
9
  • 3
    Why would you use eval? Just build the object! Commented Dec 1, 2015 at 3:30
  • Why do you think you have to do this using eval? Commented Dec 1, 2015 at 3:30
  • 2
    If there is another way, I'll take it. However, I have not been successful joining the strings into an object. To make matters more difficult, all javascript is itself ajaxed onto the page as a string. I sometimes think I should have chosen an easier career, like pediatric brain surgery or inventing nth dimensional quantum mechanics. Commented Dec 1, 2015 at 3:36
  • 1
    If the response is a string, that string probably is JSON, JSON is a string representation of a structure, in that case you should use the JSON.parse method for parsing the string. What you are trying to do is madness. It's very fragile, error-prone and an anti-pattern. Commented Dec 1, 2015 at 3:45
  • 1
    When you're including external resources in jsfiddle, using the github link directly is a bad idea. Github serves its raw files with mime type text/plain. Some web browsers, quite reasonably, refuse to interpret this as a javascript file because it is not application/javascript. Try using rawgit.com to reference these instead. Commented Dec 1, 2015 at 5:49

3 Answers 3

2

I have fixed this. The key was understanding that eval() must not ever be used, under any circumstances. (At my present skill level, at least)

Aside from the ajax injection, and JavaScript code being injected with it, here's what I was trying to do. I had these values in variables:

cu = 3;
py = 5;
fs = 7;
qz = 9;
ch = 11;
am = 13;
mi = 15;
mo = 17;

I had to create an array that was part text/part variable (I thought...). So, I tried this:

pDat = ['{value:'+cu+'}, {value:'+py+'}, {value:'+fs+'}, {value:'+qz+'}, {value:'+ch+'}, {value:'+am+'}, {value:'+mi+'}, {value:'+mo+'}'];

That didn't work. So I tried:

eval('pDat = [{value:'+cu+'}, {value:'+py+'}, {value:'+fs+'}, {value:'+qz+'}, {value:'+ch+'}, {value:'+am+'}, {value:'+mi+'}, {value:'+mo+'}']');

That worked for the array, but not for the object.

With the good advice from Vohuman, guest271314, epascarello and other good souls, I went back to the drawing board and refactored the code so that I could just do this:

(And it worked for everything - I was even able to add the variables with the color codes):

pDat = [{value:cu, color:CuCol}, {value:py, color:PyCol}, {value:fs, color:FsCol}, {value:qz, color:QzCol}, {value:ch, color:ChCol}, {value:am, color:AmCol}, {value:mi, color:MiCol}, {value:mo, color:MOCol}];

oOpt = {
    annotateDisplay : true,
    segmentShowStroke : false,
    segmentStrokeColor : "white",
    segmentStrokeWidth : 1,
    percentageInnerCutout : 0,
    animation: false,
    animationSteps : 100,
    animationEasing : "easeOutQuart",
    animateRotate : true,
    animateScale : false,
    legendTemplate : '<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>'
};

var ctx = document.getElementById("pieChart").getContext("2d");
updateChart(ctx,pDat,pOpt,true,false);

Note:

FWIW, CuCol, PyCol etc are just vars that look like this:

CuCol = '#ffe382';
PyCol = '#1bb3a5';
etc
Sign up to request clarification or add additional context in comments.

Comments

1

You are using eval for creating an array of objects:

s1 = '{value:25, color:"red"}';
s2 = '{value:5, color:"blue"}';
s3 = '{value:25, color:"palegreen"}';
s4 = '{value:10, color:"darkcyan"}';
s5 = '{value:35, color:"wheat"}';
var pieData = [ s1+s2+s3+s4+s5 ];

The above code snippet is a wrong way of doing this. Here you shouldn't create a string representation of an object (those are not valid JSON strings) when you need a real object. What you should do is:

var s1 = {value:25, color:"red"};
var s2 = {value:5, color:"blue"};
var s3 = {value:25, color:"palegreen"};
var s4 = {value:10, color:"darkcyan"};
var s5 = {value:35, color:"wheat"};
var pieData = [ s1, s2, s3, s4, s5 ];

Now pieData is an array of objects. Done!

1 Comment

Thanks m8. You guys have really made me think. Why is it that it's the rappers and dancers who wear headbands when its us coders who sometimes feel the need to wrap something around our heads because they're about to explode with the concepts with which we grapple? On the other hand, it might just be that I'm not that smart. I am open to that possibility... and on a night like tonight it feels more like a probability... Thanks for your help and advice.
1

Note, adjusted double quotes at <ul> string attributes to single quotes .

Try using String.prototype.split() , Array.prototype.map() , String.prototype.replace() with RegExp /(^[a-zA-Z]+)(?=\s|:)/g to match characters a-z case insensitive followed by space character or colon character ":" property of object string ; JSON.stringify() , JSON.parse()

pieO  = 'annotateDisplay : true,';
pieO += 'segmentShowStroke : false,';
pieO += 'segmentStrokeColor : "white",';
pieO += 'segmentStrokeWidth : 1,';
pieO += 'percentageInnerCutout : 0,';
pieO += 'animation: false,';
pieO += 'animationSteps : 100,';
pieO += 'animationEasing : "easeOutQuart",';
pieO += 'animateRotate : true,';
pieO += 'animateScale : false,';
pieO += 'legendTemplate : "<ul class=\'<%=name.toLowerCase()%>-legend\'><% for (var i=0; i<segments.length; i++){%><li><span style=\'background-color:<%=segments[i].fillColor%>\'></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"'

pieO = pieO.split(",").map(function(val, index) {
    val = val.replace(/(^[a-zA-Z]+)(?=\s|:)/g, function(match) {
      return JSON.stringify(match)
    });
    return JSON.parse("{" + val + "}")
});

console.log(pieO)

4 Comments

I know it's fun to do uncommon stuff, but this is really unnecessary. It actually doesn't make sense.
@Vohuman Requirement appear to include "I must build array and object from textual strings." stackoverflow.com/questions/34012081/… . Not certain how to evaluate whether a process "makes sense" or not ? Many errors , mistakes and also blunders have led to novel developments , or even enlightenment ?
That's creative. I said it doesn't make sense as it made the process unnecessarily complicated. I hope it helps him/her.
Gents, both your suggestions helped immensely (and he's a him). I was suffering from a combined lack of experience, training and examples. Your suggestions / examples helped me to solve the problem. When I achieve sufficient zen humility to post what worked, with you will likely need belts to keep your sides from splitting. (from laughing...)

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.