Search code examples
jqueryjsonparsingcustom-data-attribute

Why isn't my jQuery parsing this JSON from data element correctly before using it


I am experiencing some odd behavior on some JSON data I have applied to a data attribute in my HTML. I have it working using a fix, but I'm not sure why I need to apply this fix. I am using jQuery 1.9.0.

Case 1 - working without $.parseJSON()

http://reelfilmlocations.co.uk/browse-locations/

On this page I have data attributes applied to the icons below the images, I'll use the map icon as an example:

map icon

the HTML looks like this:

    <img
       src="/images/Icons/map circle.fw.png" width="24" height="24" 
       class="icon mapLink"
       data-location='{
           "id":"<?php echo($row_rs_locations['id_loc']);?>",
            "slug":"<?php echo($row_rs_locations['slug_loc']);?>",
            "page":"<?php echo($cur_page);?>",
            "lat":"<?php echo($row_rs_locations['maplat_loc']);?>",
            "lng":"<?php echo($row_rs_locations['maplong_loc']);?>",
            "pinType":"loc",
            "name":"<?php echo($row_rs_locations['name_loc']);?>",
            "linkType":"list"
      }'
    />
    

The JSON Object:

{ "id":"5", "slug":"boston-manor-house-and-park", "page":"1", "lat":"51.492341", "lng":"-0.3186064000000215", "pinType":"loc", "name":"Boston Manor House and Park", "linkType":"list" }

I checked on http://jsonlint.com/ and this is indeed valid JSON

I have the following jQuery to run when the a map icon is clicked

$('.wrapper').delegate('.mapLink','click',function() {
            var myData = $(this).data('location');
            console.log(myData); // correctly logs json object
            $('.middle_section').hide();
            $('#mapContent').show();
            createMarkerWithInfo(myData, true); 
        })

everything works as expected the data-location element is read in as JSON and I can use it as a JSON object without doing anything else


Case 2 - need to use $.parseJSON()

http://2012.reelfilmlocations.co.uk/browse-locations/

This is almost a duplicate of the above case (this version will be optimized for mobile devices)

The code is pretty much the same except the click event retrieves the data-location element but as text not a JSON object I need to parse it using $.parseJSON(myData) before I can use it.

$('.wrapper').delegate('.mapLink','click',function() {
            //console.log('mapLink clicked');
            var myData = $(this).data('location');
            console.log(myData);// outputs text not a json object
            myData = $.parseJSON(myData) //parse the data
            console.log(myData);// outputs a JSON object
            $('.middle_section').hide();
            $('#mapContent').show();
            createMarkerWithInfo(myData, true); 
        })

I'm not understanding why, in two scripts which are exactly the same, I have to use $.parseJSON for one, and on the other I don't. It seems like weird behaviour to me, can anyone enlighten me?


Solution

  • Your first link, where it's working, is using jQuery 1.9.0.

    Your second link, where it isn't working, is using jQuery 1.7.2.

    The reason it isn't working is that the regular expression used by jQuery 1.7.2 (the version you're using on that site), which is /^(?:\{.*\}|\[.*\])$/, fails to detect that the attribute contains correct JSON and so doesn't pass it on to $.parseJSON.

    The regular expression used by jQuery 1.10.2, which is /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, does correctly detect that it has JSON, and does pass it on to $.parseJSON. (That expression seems rather permissive to me, but if it passes on something invalid and the parse fails, it continues with the string.) Persumably they fixed the regex somewhere between 1.7.2 and 1.9.

    Here's a test page using the JSON from the first mapLink on your page using jQuery 1.7.2:

    <div id="test" data-location='{
                                  "id":"1",
                                  "slug":"watermans-arts-centre",
                                  "page":"1",
                                  "lat":"51.485768",
                                  "lng":"-0.29806459999997514",
                                  "pinType":"loc",
                                  "name":"Watermans Arts Centre",
                                  "linkType":"list"
                                  }'></div>
    <script>
      (function() {
        var test = $("#test");
        display("jQuery v" + test.jquery);
        display("typeof data: " + typeof test.data("location"));
    
        function display(msg) {
          $("<p>").html(String(msg)).appendTo(document.body);
        }
      })();
    </script>
    

    ...which outputs:

    jQuery v1.7.2
    
    typeof data: string

    ...and here's that same page using jQuery 1.10.2, which outputs:

    jQuery v1.10.2
    
    typeof data: object