Loading json files from a javascript program

I have a javascript program embedded in a specific page within a Hugo site to render some interactive graphs. It needs to read JSON data files. Note that this is different from the common case in the forum where you want a Hugo template to read a JSON file.

I’ve explored two options, one isn’t working and the other seems unsatisfying.

The one that doesn’t work is to put the json files with the page containing the JS that needs it. That is, I have

-- content
   -- safeseats
      -- _index.md
      -- json
         -- ridings.json

I haven’t been able to get Hugo to serve /safeseats/json/ridings.json. I believe there is a setting in the config.toml file that’s needed, but so far I haven’t gotten it to work. Currently I have safeseats = ["json"]. I’m finding the documentation at Custom Output Formats to be very confusing.

A second approach IS working, but as I said, feels unsatisfying and needs improvement. This approach puts the json files as assets in assets/json/riding.json, etc.

I know from the Hugo Pipes Introduction that magic happens to make files in assets visible publicly. So I have the following in a custom-footer partial:

{{ range $json := slice "json/ridings.json" "json/elections.json" "json/votesVsTime.json" }}
	{{ $res := resources.Get $json }}
	{{ $res.RelPermalink }}
{{ end }}

BUT… this is a global concern – making sure that the files get moved to the public folder. But the custom-footer is a local concern – a specific page. Surely there is a better place to do this, but what is it?

Or am I approaching this all wrong in the first place?

I’m currently running version 0.72.0/extended.

The JSON is a Page Resource of /content/safeseats/_index.html.

Therefore to call it from the templates you would need to use one of the Page Resources Methods

Thanks for the reply, @alexandros. However, I want to load the JSON from a javascript program, embedded in a Hugo site. I do not want to call it from a template, so I don’t think the page resource methods are applicable. Further thoughts welcome!

I like the approach outlined by @alexandros. You could embed the JSON within the generated HTML.

structure

content
└── post
    └── post-1
        ├── json
        │   ├── bar.json
        │   └── foo.json
        └── index.md

content/post/post-1/json/foo.json

{
  "a": 1,
  "b": 2,
  "c": 3
}

content/post/post-1/json/bar.json

{
  "x": 7,
  "y": 8,
  "z": 9
}

layouts/post/single.html

{{ define "main" }}
  <h1>{{ .Title }}</h1>
  {{ .Content }}

  {{ range (.Resources.Match "json/*") }}
    <script type="application/json" id="{{ replace (path.Base .Name) `.` `-` }}">
      {{ .Content | safeJS }}
    </script>
  {{ end }}

  <script>
    var foo = JSON.parse(document.getElementById('foo-json').innerHTML);
    alert (foo.a+foo.b+foo.c);
  </script>

  <script>
    var bar = JSON.parse(document.getElementById('bar-json').innerHTML);
    alert (bar.x+bar.y+bar.z);
  </script>

{{ end }}

Your scripts, data, and HTML all contained within a single file.

2 Likes

Thanks for the very explicit description of the idea, @jmooring.

Does it make a difference to your opinion knowing that the JSON data file is 450K? It seems better to me to have the Javascript program read it directly from the server rather than embedding it in the HTML.

<script>
   var data = LoadDataFromServer(document.location.origin + "/json/myGraphData.json");
   document.querySelector("#myGraph").appendChild( renderGraph(data) );
</script>

But how do I do the first line (elegantly)? I’ve got the second line covered.

No, in fact it’s one less call to the server. And since the data is only used on one page, there’s no benefit to caching it as a separate file. Finally, regardless of whether the JSON is embedded or downloaded as a separate file, a properly configured HTTP server (Apache, nginx, etc.) will compress (Gzip) the data before serving to the client. Although it obviously depends on the actual data, in general JSON compresses really well (70-80 percent reduction, sometimes more).

Assuming you embed the data following my example above, it would look just like my example above:

var data = JSON.parse(document.getElementById('myGraphData-json').innerHTML);

Thanks for sticking with me, @jmooring. I appreciate the help.

In spite of your reassurances, I still prefer to keep my graph data separate from the HTML. It feels cleaner to me and allows me to develop/test the javascript without Hugo.

In any case, what I finally did was put my data in the same directory as the page containing the javascript. That is, content/safeseats/_index.md is the page containing the javascript program. content/safeseats/myGraphData.json contains the data. The javascript program can then read the data from http://localhost:1313/safeseats/myGraphData.json.

I had initially tried to have the data in a subdirectory of safeseats. That didn’t work; don’t understand why.