117

I have this JSON file I generate in the server I want to make accessible on the client as the page is viewable. Basically what I want to achieve is:

I have the following tag declared in my html document:

<script id="test" type="application/json" src="http://myresources/stuf.json">

The file referred in its source has JSON data. As I've seen, data has been downloaded, just like it happens with the scripts.

Now, how do I access it in Javascript? I've tried accessing the script tag, with and without jQuery, using a multitude of methods to try to get my JSON data, but somehow this doesn't work. Getting its innerHTML would have worked had the json data been written inline in the script. Which it wasn't and isn't what I'm trying to achieve.

Remote JSON Request after page loads is also not an option, in case you want to suggest that.

Rimian
  • 36,864
  • 16
  • 117
  • 117
ChuckE
  • 5,610
  • 4
  • 31
  • 59
  • 3
    Instead of a json file, make it a javascript file that assigns the object to a variable. The other approach is to use ajax. – Asad Saeeduddin Nov 22 '12 at 14:50
  • 3
    The first suggestion is the current implementation. I would like not to do it because I'm using behaviour to deliver structure. I'd prefer to use structure for structure (if I want JSON, i'll get JSON). Second suggestion is not wanted (I need this data for the initialization process). – ChuckE Nov 22 '12 at 15:00
  • 1
    @ChuckE through a ` – Pointy Nov 22 '12 at 15:03
  • 3
    @Pointy through a – ChuckE Nov 22 '12 at 15:25
  • 2
    "Remote JSON Request after page loads is also not an option, in case you want to suggest that." ... how is a JSON request so much different than a request sent by a ``? They're both going to be doing GET calls against your server. – Ben Lesh Nov 27 '12 at 02:26

10 Answers10

131

You can't load JSON like that, sorry.

I know you're thinking "why I can't I just use src here? I've seen stuff like this...":

<script id="myJson" type="application/json">
 { 
   name: 'Foo' 
 }
</script>

<script type="text/javascript">
    $(function() {
        var x = JSON.parse($('#myJson').html());
        alert(x.name); //Foo
     });
</script>

... well to put it simply, that was just the script tag being "abused" as a data holder. You can do that with all sorts of data. For example, a lot of templating engines leverage script tags to hold templates.

You have a short list of options to load your JSON from a remote file:

  1. Use $.get('your.json') or some other such AJAX method.
  2. Write a file that sets a global variable to your json. (seems hokey).
  3. Pull it into an invisible iframe, then scrape the contents of that after it's loaded (I call this "1997 mode")
  4. Consult a voodoo priest.

Final point:

Remote JSON Request after page loads is also not an option, in case you want to suggest that.

... that doesn't make sense. The difference between an AJAX request and a request sent by the browser while processing your <script src=""> is essentially nothing. They'll both be doing a GET on the resource. HTTP doesn't care if it's done because of a script tag or an AJAX call, and neither will your server.

Ben Lesh
  • 107,825
  • 47
  • 247
  • 232
  • 6
    Great answer. When you say "the script tag being 'abused'" you mean that is a wrong (maybe not wrong, but "creative") use of the script tag? Your n. 2 option is the one we already have in production, I was looking for a strictly json/no-js solution, out of pure experimentation (I'm fine with it not being possible if I'm sure it is). Concerning the final point, I need this information before onload event, and I don't want to make the whole initialization depend of an asynchronous request which may vary in completion time. This is the key difference between Ajax call and script tag. – ChuckE Nov 27 '12 at 08:51
  • 1
    No, I don't think it's "wrong", per say, just... "creative" is probably a good word for it. If actually writing the JSON into the ` – Ben Lesh Nov 27 '12 at 13:41
  • yeh, the whole challenge was loading it using the script tag src attribute and "obfuscate" this information in the document. – ChuckE Nov 27 '12 at 14:43
  • Well, you can't really hide data from users in a client-side browser app. They can just go into their browser's developer tools and set a breakpoint in the JavaScript and examine objects however they like. – Ben Lesh Nov 27 '12 at 16:29
  • I don't want to hide data from the user, I want to hide js data from HTML (keep HTML in the document, keep javascript in javascript) – ChuckE Nov 28 '12 at 08:48
  • hii. can you tell me how can i use your function to get json data from src attribute. because i don't have body of script tag as u defined { name: 'Foo' } but in my case this should fill dynamically from url – Jaydipsinh Sep 23 '13 at 06:04
  • @Jaydipsinh You can't load JSON like that. If you want to load it from a URL, you'd just use ajax. `$.get('whatever.json');` – Ben Lesh Sep 23 '13 at 13:08
  • @blesh: but i got json data from other port so i got cross-origin problem, can't make ajax call and i've tried with – Jaydipsinh Sep 23 '13 at 14:20
  • 1
    @Jaydipsinh, then you need to resolve your CORS issues, and use Ajax. There's a reason browsers disallow this sort of behavior. Most browsers won't even let you hack your way around CORS with an iframe anymore. – Ben Lesh Sep 23 '13 at 16:09
  • I'm writing a custom web app for reporting api test results stored in json that the developer will access directly from the file system and Chrome disallows ajax requests to file:// unless started with a special flag for security reasons, so unfortunately such abuse has become a viable option for me in this scenario. – Kyle Jul 27 '18 at 15:06
  • Except it doesn't work at all with an empty script element with a src attribute pointing to an external file. Sigh. – Kyle Jul 27 '18 at 15:21
  • Difference between Ajax and script-load is essetially nothing when doing a GET.. Does it mean Ajax also has exactly the same restrictions? With CORS on server the Access-Control-Allow must be set? I have read script-loading is more allowing than Ajax and because of that is most preferred in script-loaders. –  Aug 04 '19 at 19:52
20

Another solution would be to make use of a server-side scripting language and to simply include json-data inline. Here's an example that uses PHP:

<script id="data" type="application/json"><?php include('stuff.json'); ?></script>
<script>
var jsonData = JSON.parse(document.getElementById('data').textContent)
</script>

The above example uses an extra script tag with type application/json. An even simpler solution is to include the JSON directly into the JavaScript:

<script>var jsonData = <?php include('stuff.json');?>;</script>

The advantage of the solution with the extra tag is that JavaScript code and JSON data are kept separated from each other.

Lea Rosema
  • 1,100
  • 16
  • 31
13

It would appear this is not possible, or at least not supported.

From the HTML5 specification:

When used to include data blocks (as opposed to scripts), the data must be embedded inline, the format of the data must be given using the type attribute, the src attribute must not be specified, and the contents of the script element must conform to the requirements defined for the format used.

btx9000
  • 438
  • 4
  • 10
  • 1
    Seem to be a policy to handle data as more sensitive than JS and CSS. –  Aug 04 '19 at 19:27
8

While it's not currently possible with the script tag, it is possible with an iframe if it's from the same domain.

<iframe
id="mySpecialId"
src="/my/link/to/some.json"
onload="(()=>{if(!window.jsonData){window.jsonData={}}try{window.jsonData[this.id]=JSON.parse(this.contentWindow.document.body.textContent.trim())}catch(e){console.warn(e)}this.remove();})();"
onerror="((err)=>console.warn(err))();"
style="display: none;"
></iframe>

To use the above, simply replace the id and src attribute with what you need. The id (which we'll assume in this situation is equal to mySpecialId) will be used to store the data in window.jsonData["mySpecialId"].

In other words, for every iframe that has an id and uses the onload script will have that data synchronously loaded into the window.jsonData object under the id specified.

I did this for fun and to show that it's "possible' but I do not recommend that it be used.


Here is an alternative that uses a callback instead.

<script>
    function someCallback(data){
        /** do something with data */
        console.log(data);

    }
    function jsonOnLoad(callback){
        const raw = this.contentWindow.document.body.textContent.trim();
        try {
          const data = JSON.parse(raw);
          /** do something with data */
          callback(data);
        }catch(e){
          console.warn(e.message);
        }
        this.remove();
    }
</script>
<!-- I frame with src pointing to json file on server, onload we apply "this" to have the iframe context, display none as we don't want to show the iframe -->
<iframe src="your/link/to/some.json" onload="jsonOnLoad.apply(this, someCallback)" style="display: none;"></iframe>

Tested in chrome and should work in firefox. Unsure about IE or Safari.

kemicofa ghost
  • 16,349
  • 8
  • 82
  • 131
5

place something like this in your script file json-content.js

var mainjson = { your json data}

then call it from script tag

<script src="json-content.js"></script>

then you can use it in next script

<script>
console.log(mainjson)
</script>
hossein sedighian
  • 1,711
  • 1
  • 13
  • 16
4

I agree with Ben. You cannot load/import the simple JSON file.

But if you absolutely want to do that and have flexibility to update json file, you can

my-json.js

   var myJSON = {
      id: "12ws",
      name: "smith"
    }

index.html

<head>
  <script src="my-json.js"></script>
</head>
<body onload="document.getElementById('json-holder').innerHTML = JSON.stringify(myJSON);">
  <div id="json-holder"></div>
</body>
Karan
  • 41
  • 1
3

If you need to load JSON from another domain: http://en.wikipedia.org/wiki/JSONP
However be aware of potential XSSI attacks: https://www.scip.ch/en/?labs.20160414

If it's the same domain so just use Ajax.

krempelj
  • 31
  • 1
  • 4
  • 2
    JSONP does not work with JSON-formatted results. Also, the JSONP parameters passed as arguments to a script are defined by the server… which you might not have access to. – e-sushi Mar 03 '15 at 11:25
2

Check this answer: https://stackoverflow.com/a/7346598/1764509

$.getJSON("test.json", function(json) {
    console.log(json); // this will show the info it in firebug console
});
Community
  • 1
  • 1
L.Grillo
  • 960
  • 3
  • 12
  • 26
1

Another alternative to use the exact json within javascript. As it is Javascript Object Notation you can just create your object directly with the json notation. If you store this in a .js file you can use the object in your application. This was a useful option for me when I had some static json data that I wanted to cache in a file separately from the rest of my app.

    //Just hard code json directly within JS
    //here I create an object CLC that represents the json!
    $scope.CLC = {
        "ContentLayouts": [
            {
                "ContentLayoutID": 1,
                "ContentLayoutTitle": "Right",
                "ContentLayoutImageUrl": "/Wasabi/Common/gfx/layout/right.png",
                "ContentLayoutIndex": 0,
                "IsDefault": true
            },
            {
                "ContentLayoutID": 2,
                "ContentLayoutTitle": "Bottom",
                "ContentLayoutImageUrl": "/Wasabi/Common/gfx/layout/bottom.png",
                "ContentLayoutIndex": 1,
                "IsDefault": false
            },
            {
                "ContentLayoutID": 3,
                "ContentLayoutTitle": "Top",
                "ContentLayoutImageUrl": "/Wasabi/Common/gfx/layout/top.png",
                "ContentLayoutIndex": 2,
                "IsDefault": false
            }
        ]
    };
0

While not being supported, there is an common alternative to get json into javascript. You state that "remote json request" it is not an option but you may want to consider it since it may be the best solution there is.
If the src attribute was supported, it would be doing a remote json request, so I don't see why you would want to avoid that while actively seeking to do it in an almost same fashion.

Solution :

<script>
    async function loadJson(){
        const res = await fetch('content.json');
        const json = await res.json();
    }
    loadJson();
</script>

Advantages

  • allows caching, make sure your hosting/server sets that up properly
  • on chrome, after profiling using the performance tab, I noticed that it has the smallest CPU footprint compared to : inline JS, inline JSON, external JS.