passing in a JSON object in HTML DOM - javascript
I am experimenting with a charting package called Highcharts (some of you may be familiar with it but regardless the problem is not related to Highcharts per se). What I wanted to do was have my PHP generated HTML embed a JSON object into the DOM which would then be picked up by a static jQuery listening function. Here's what it looks like:
// Static JS file that get's loaded with every page load and
// and listens for a class with ".highchart_config".
// When it finds a config class it then looks in the attribute "data-chart"
// for the JSON configuration object
jQuery.noConflict();
jQuery(function($) {
$(document).ready(function() {
$(".highchart_config").each(function(index) {
var config_obj = $(this).attr('data-chart');
chart = new Highcharts.Chart( config_obj );
});
});
});
And then the HTML is as follows:
<div class="highchart_config" data-chart=' {chart: {"renderTo":"chart2","defaultSeriesType":"column"},title: {"text":"Monkies are Happy Animals"},xAxis:{"categories":["Apples","Oranges","Pears","Grapes","Bananas"],"min":null,"title":""},yAxis: {"min":0,"title":{"text":"Total fruit consumption"}},legend: {"align":"center","x":0,"verticalAlign":"bottom","y":0,"floating":false,"backgroundColor":null,"borderColor":"#CCC","borderWidth":1,"shadow":false,"reversed":true},tooltip: { formatter: function() { return this.series.name + ":" + this.y + " "}},plotOptions: {"column":{"stacking":"normal","dataLabels":{"enabled":false}}},series: [{"name":"Running","data":[5,3,4,7,2]},{"name":"Cycling","data":[2,2,3,2,1]},{"name":"Lifting","data":[3,4,4,2,5]}]}'></div>
Using a debugger I can see this working by placing a breakpoint on the line where Highcharts object instantiation takes place. When the breakpoint is hit I print the value of "chart_obj" which comes out as:
{chart: {"renderTo":"chart2","defaultSeriesType":"column"},title: {"text":"Monkies are Happy Animals"},xAxis:{"categories":["Apples","Oranges","Pears","Grapes","Bananas"],"min":null,"title":""},yAxis: {"min":0,"title":{"text":"Total fruit consumption"}},legend: {"align":"center","x":0,"verticalAlign":"bottom","y":0,"floating":false,"backgroundColor":null,"borderColor":"#CCC","borderWidth":1,"shadow":false,"reversed":true},tooltip: { formatter: function() { return this.series.name + ":" + this.y + " "}},plotOptions: {"column":{"stacking":"normal","dataLabels":{"enabled":false}}},series: [{"name":"Running","data":[5,3,4,7,2]},{"name":"Cycling","data":[2,2,3,2,1]},{"name":"Lifting","data":[3,4,4,2,5]}]}
That looks "right" to me but it doesn't work. Instead the instantiation of the object fails as the config_obj is somehow malformed. To make sure I wasn't making some stupid syntax error I cut and paste the value in config_obj and put it into a static JS file that looks like this:
$(function () {
var chart;
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {"renderTo":"chart2","defaultSeriesType":"column"},title: {"text":"Monkies are Happy Animals"},xAxis: {"categories":["Apples","Oranges","Pears","Grapes","Bananas"],"min":null,"title":""},yAxis: {"min":0,"title":{"text":"Total fruit consumption"}},legend: {"align":"center","x":0,"verticalAlign":"bottom","y":0,"floating":false,"backgroundColor":null,"borderColor":"#CCC","borderWidth":1,"shadow":false,"reversed":true},tooltip: { formatter: function() { return this.series.name + ":" + this.y + " "}},plotOptions: {"column":{"stacking":"normal","dataLabels":{"enabled":false}}},series: [{"name":"Running","data":[5,3,4,7,2]},{"name":"Cycling","data":[2,2,3,2,1]},{"name":"Lifting","data":[3,4,4,2,5]}]
});
});
});
This "hardcoded" method works and yet the instantiation call should have precisely the same configuration object passed in. I'm at a loss now how to proceed. I have been reading other posts on stackoverflow around this topic but can't find anything to help me with my specific problem. Any and all help is greatly appreciated.
UPDATE:
I have no tried ... to no avail using both data() and attr() methods and in both cases with and without a call to JSON.parse(config_obj). It DOES appear that the problem is related to config_obj being treated as a string so in the debugger I decided to assign a variable "test" to the cut-and-pasted string results of config_obj without the exterior quotation marks. It works fine so it's clearly a well structured JSON string but getting it converted to a string is still eluding me. Below I have an image of my debugging session which shows three things:
First I get an error when using the JSON.parse() function on my config_obj string (that's true regardless if I used data() or attr() to retrieve config_obj from the DOM)
If I instead just cut-and-paste the text into a test variable called "test" it is recognised as a valid JS object
If I use the JSON.stringify() method on the test object it converts back to a string version that is CLOSE to the same as my config_obj variable ... the difference being that the first level attributes in the object have quotation marks around them. This might be a hint at what's going wrong but I still haven't cracked this nut ... any help would be greatly appreciated.
When you get the attributes value - using .attr() - what you're being returned is a string. You'll need to parse that string to turn it into the actual object, so change the following line to:
chart = new Highcharts.Chart( JSON.parse(config_obj) );
It's the JSON.parse() function that's the important part.
Also, as a note, if you're using data-* attributes, it's better to use the .data() function, so you'd change the other line to:
var config_obj = $(this).data('chart');
As you may have seen in my "update" to the question I had found a variation in the string versions of the JSON object between my original object and the one I created by cut-and-pasting this same string into an object and then running JSON.stringify() on it.
This variation -- including double quote markers around object names -- seems to be important for it to work correctly. If you pass it in this way using jQuery's .data() method than it automatically converts it to a JSON object and there's no need to directly call JSON.parse().
I still find it odd that there is a stricter standard to convert a string to an object with JSON's parse() method than there is within JS itself and I'd be interested if anyone has any theories on this. In either event, wanted to thank #Anthony, #DCoder and everyone else who helped.
Here is the working DOM entry:
<div class="highchart_config" data-chart='{"chart":{"renderTo":"chart2","defaultSeriesType":"column"},"title":{"text":"Monkies are Happy Animals"},"xAxis":{"categories":["Apples","Oranges","Pears","Grapes","Bananas"],"min":null,"title":""},"yAxis":{"min":0,"title":{"text":"Total fruit consumption"}},"legend":{"align":"center","x":0,"verticalAlign":"bottom","y":0,"floating":false,"backgroundColor":null,"borderColor":"#CCC","borderWidth":1,"shadow":false,"reversed":true},"tooltip":{},"plotOptions":{"column":{"stacking":"normal","dataLabels":{"enabled":false}}},"series":[{"name":"Running","data":[5,3,4,7,2]},{"name":"Cycling","data":[2,2,3,2,1]},{"name":"Lifting","data":[3,4,4,2,5]}]}'></div>
And the JS that takes this DOM entry as input is:
jQuery.noConflict();
jQuery(function($) {
$(document).ready(function() {
$(".highchart_config").each(function(index) {
var config_obj = $(this).data('chart');
chart = new Highcharts.Chart( config_obj );
});
});
});
Related
Capturing entire line syntax plus string output for debugging
I have a method that runs in my vue js application methods: { searchFunction(helper) { //helper.addFacetRefinement('deal', 'deal').search(); helper.addFacetRefinement('price_per_night', '>'+parseInt(this.slider_amount)).search(); }, The helper should work if it forms like this helper.addFacetRefinement('price_per_night', '> 100')).search(); however, it doesn't and i want to know why. Is there a way i can print the entire line plus the syntax helper.addFacetRefinement('price_per_night', '>'+parseInt(this.slider_amount)).search(); and variable values to see how it was formed and know how i can make ammends. Thanks.
You could use a temporary variable for your string generation, then console.log it out and use it in your actual search call. Something like let searchCondition = '>' + parseInt(this.slider_amount); console.log(searchCondition); helper.addFacetRefinement('price_per_night', searchCondition).search(); Since this is the only dynamic part of your search() invocation, this should be sufficient?
Can't access object in jquery (prevObject?)
A function in my WP plugin has just randomly (as far as I can tell) stopped working. Here's the code in question: window.send_to_editor = function(html) { var classes = jQuery('img',html).attr('class'); var items = classes.split(" "); ... more stuff here } I've confirmed that the html variable is indeed an img html tag. Here's what firebug shows when I do a console.log of the object (console.log(jQuery('img',html));): Object[] context -> undefined jquery -> "1.11.2" length -> 0 prevObject -> Object[img.alignnone.size-full.wp-image-1234 name.jpg] And the error it shows is classes is undefined. I figure there's something wrong with the object I get, but this used to work recently and I'm not aware of any changes in the site that could have caused this. I'd appreciate any input on this. EDIT: More info. This happens with two plugins which are supposed to be unrelated (made by different people). It happens when, after uploading an image to the server (or selecting a previously uploaded picture) you try to insert it into the post. As I said before this error has appeared out of nowhere, it was working as intended a couple days ago. The only thing I can think of that has changed since then is the domain name, but I can't see how that could be related.
The jQuery selector always returns a jQuery object, but when the length is 0 then no elements were found matching the selector that you provided. In your example you've confirmed that nothing is selected as the length of the jQuery object is 0. Perform a check whether an element was selected like this: var $els = jQuery('img',html), classes; if ($els.length) { classes = $els.attr("class"); } Keep in mind that your DOM query is limited by what you pass in as the html parameter. If you simply want to find the images on the page do: var $els = jQuery('img');
I finally managed to fix this; the key was parsing the html string variable into proper HTML, using jQuery.parseHTML(). Thanks to everyone who helped!
javascript literals from C# - avoiding warnings
First off, this code does work, but it gives me a low level of annoyance that I'd like to be rid of. I have a .cshtml page that is built using the razor syntax. There is a big, nasty, knockout object living behind the scenes to which many things on the page are bound. Currently, when instantiating that knockout model, I'm doing so by serializing the C# viewmodel object in question within a string literal like below. <script type="text/javascript"> $(document).ready(function() { var data = #Html.Raw(Json.Encode(Model)); var contentListingModel = new ContentListingModel(data); ko.applyBindings(contentListingModel, $('#pageRoot').get(0)); }); </script> Like I said, the code works. However, on the line with the #Html.Raw call, I get a warning. Visual Studio believes there is a syntax error there (there isn't, after it is rendered). Now, it totally makes sense WHY the thing believes there is a syntax problem there. But I would love to get rid of the warning by coding in a way that doesn't trigger this issue (I realize I could hide the warning or do any number of other things), but I just want it to not show in cases where I'm serializing C# objects into JSON and stuffing them into javascript on the page. Any ideas? I accept fully that it is pedantic and petty to ask about this one, since the code works perfectly well and is seemingly clean, but it annoys me.
The IDE is smart enough to accept lines which consist purely of Razor, so you can write: #Html.Raw( "var data= " + Json.Encode(Model) + ";" ) alert(data); If the (assumed) implicit global bothers you (e.g. it triggers a Resharper warning), split the declaration and assignment. var data; // javascript #Html.Raw( "data= " + Json.Encode(Model) + ";" ) // all razor Which produces at runtime: var data; data = {"foo": "bar"};
'You Can Just Serialize Your Model To Json In Your ActionMethod , And Pass It To Your View Through ViewData Or ViewBag And Simply Pass It To ViewModel With Html.Raw , Something Like This : //In Your ActionMethod var serializer = new JavaScriptSerializer(); Viewdata["SomeName"] = serializer.Serialize(model); //In Your cshtml #{ string data = (string)Viewdata["SomeName"]; } $(document).ready(function() { var contentListingModel = new ContentListingModel('#Html.Raw(data)'); ko.applyBindings(contentListingModel, $('#pageRoot').get(0)); });
the javascript debugger ignore the razor code and see this var data = ; which is a syntax error, replace this var data = #Html.Raw(Json.Encode(Model)); with this, and the warning will be gone. var data #('=') #Html.Raw(Json.Encode(Model));
Parsing a string returned from ckeditor using javascript string methods
I am trying to get a certain area of data out from ckeditor. In order to do that I use the following code function get_body_html(){ var email = CKEDITOR.instances['message'].getData(); var before_body = header_to + to + to_subject + subject + subject_body; var s_index = email.indexOf(before_body)+before_body.length; var e_index = email.indexOf(body_footer); return email.substring(s_index,e_index); } For some reason that works when I do this on page load CKEDITOR.instances.message.setData(header_to + to + to_subject+ subject + subject_body + body_text + body_footer); get_body_html(); it works correctly and gives me the same string that is contained in body_text. But when I do this body_text = get_body_html(); CKEDITOR.instances.message.setData(header_to + to + to_subject + subject + subject_body + body_text + body_footer); in an onclick function it gets the wrong indexs somehow. Sometimes it can't find the string and returns -1 other times it just gets a weird index that doesn't make sense. These index variations only happen when my code is changed to tackle the problem a different way. So if it is the wrong indices like -5 and 2 then those would continue to be the wrong indices until I made a code change.
There are two facts that you should know about editor.setData. In some cases it is asynchronous (it depends on the type of editor). That's why it also accepts a callback. Therefore any code that is meant to be executed after setData() should be executed in that callback. It never is asynchronous before editor is ready. In this period (between editor initialization and instanceReady event) it works in a different mode - it just caches the set value and on getData() it returns exactly that value. So, as I see on page load you call synchronously setData() and getData() - your function works because you get the value you're expecting to get. But then, when you try to getData() when editor is already ready you get the HTML parsed, fixed, processed and perhaps differently formatted by CKEditor. I guess that your indexOf() checks are not enough to handle this. You have to rethink your function - e.g. regexp can help. What also can help is removing htmlwriter plugin, which formats HTML in a way which may make it harder for you to work with it. E.g.: config.removePlugins = 'htmlwriter';
I was able to get it to work. So the htmlwriter was one of the problems because it must add spaces in between by HTML tags. The other issue I found is that it strips some of the semicolons out in some of the style attributes. Overall CKEditor does a lot of formatting of the source which makes it very hard to index correctly but it's pretty much a trial and error thing. I ended up using the search JavaScript method for strings which can take a regular expression but I used it the same way indexOf would be used so I don't really know if that made a difference or not.
convert string to json and than read the json value
First of all, I'm fairly new to json, so please forgive me if I've made a terrible mistake. I've got some code that gets a json object from a website using YQL It returns it as a string. So now I want to parse this into a json object and than read it. This is my code: $.getJSON("http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url=%22http://iphone-api.uitzendinggemist.nl/v1/episodes.json%22%20and%20xpath=%27*%27&format=json", function(data) { console.log(data); content = data.query.results.html.body.p; json = JSON.stringify(eval("(" + content + ")")); str = json.revoked; $('#table').append('<li>' + str + '</li>'); }); JS fiddle I just can't figure out why this gives me undifined, instead of the value it should give. So now my question was if someone here knows why it isn't working properly.
The json variable is an array, you need to access an index. string = json[0].revoked;
You have many many many errors in your code. You should try to understand each step that you are doing, it looks like you don't. Here's a fork of your code that does something, I'm not sure what you want it to do. I'll tell you few things you did wrong: Use var keyword when declaring new variables within functions Don't parse JSON using eval(), but use some parser. E.g. $.parseJSON(). Using eval() is a security risk, as returned script WILL be executed on client and you should only be interested in getting data. When constructing HTML, take care to encode text that you want displayed. In your case, don't concatenate strings ('<li>' + str + '</li>'). You can use jQuery ($('<li>').text(str)). Don't add li elements to a table element. Either add them to ul or ol elements, or in case of tables create rows and cells. It is completely unclear why you would eval, and them stringify an object. You end up with same exact data.