Display a list of items via data json file


#1

Hi,

I tried to achieve a list of items in connection with data driven content.
I have a section with authors and would like to associate a books list per author (bibiliography).
The content structure is as follows:

content
  auteurs
  _index.md
     auteur1
       index.md
       cover.jpg
       	data
       	  bibliography.json
     auteur2
       index.md
       cover.jpg
       	data
       	  bibliography.json

In the bibliography.json file I list all books written by the given author.

I tried to display the bibliography through the following partial:

{{ if .Data.bibliography }}
{{ $bibliography := .Data.bibliography }}
<section>
  <h2>{{ $bibliography.title }}</h2>
  <div>
    {{ range $index, $element := $bibliography.bibliography }}
    <ul>
        <li>{{ $element.title }}
          <p>{{ $element.description }}</p>
      	</li>
    </ul>
{{ end }}
</div>
</section>
{{ end }}

But nothing happens. Any idea on how to implement this ?
Thanks in advance


#2

If you access .Data Hugo expects the file to be in the data directory in the root of your project. Did you try that?

Hope this helps.


#3

Yes, it works when I put the json file in data directory in the root of the project (and change the .Data.bibliography to .Site.Data.bibliography in the partial file.
But I would like if possible to have one different file per author and to locate this file in the author directory (in a certain extent similar as bundle feature).
I don’t know if it is possible or not.


#4

Understand. Then you probably have to use page bundles (index.md instead of _index.md). Here’s a great article from @regis about page bundles: https://regisphilibert.com/blog/2018/01/hugo-page-resources-and-how-to-use-them/


#5

Sorry to come back again since I still have difficulties to implement the feature even after reading the great article from @regis (by the way his blog is very helpful and comprehensive to better use Hugo):
Thanks to the article I slightly modify my partial but still not working
The updated code is as follows:

{{ with .Resources.Match "**.json" }}
{{ $file := $.Page.Resources.GetMatch (.Get 0)}}
{{ $data := getJSON "content" $file }}
<section>
 <h2>{{ $file.title }}</h2>
 <div>
{{ range $index, $element := $file.books}}
<ul>
 <li>{{ $element.title }}
   <p>{{ $element.description }}</p>
 </li>
</ul>
{{ end }}
</div>
</section>
{{ end }}

I got the following error message:

execute of template failed: template: _default\single.html:25:41: executing "main" at <.Get>: can't evaluate field Get in type resource.Resources

Any idea ?


#6

Hey there and thanks for your kind comments.

Looking at you’re code it seems like you’re doing this from a shortcode am I right ?

Because you are inside a with context the .Get is tested on the Page Resource rather Thant the shortcode. So you need to invoke the root context with $.Get

Also why the with is not on the page $.Page.Resources if I may ask (I’m surprised it works but it may be that the resources are passed on to the shortcode context theses days.

At any rate. You should use transform.Unmarshal rather than getJSON as the latter only take a url and you’re working with a Resource’s content.


#7

Thank you for the swift answer.
Note that my code skills are very limited and I don’t catch all the meaning of your comments.
Actually, I tried to implement it through a partial (not a shortcode) and the partial doesn’t work.
I have no idea of what you are talking of about transform.Unmarshal. I am going through the Hugo Forum to understand the feature. I found this post in the forum dealing with something similar but still unclear for me.
I am still stuck !


#8

You should definitely use a partial and as you caught me on slow morning, I took the liberty to right one for you (untested), with heavy commenting. Please don’t simply copy/paste it, but try and understand every comments in it. This way, if I missed something (As I don’t know anything about the project) you’ll be able to fix it yourself :muscle:

{{/* 
	Print a list of authors retrieved from a json page resources
	
	@author 🤷‍♂️

	@context Page

	@example:
	  {{ partial "authors" . }} 
*/}}

{{/* Presuming your json file is always called the same 
we look for it in the page bundle with GetMatch (which returns only one resource, contrary to Match which returns a slice of several) */}}
{{ with .Resources.GetMatch "**authors.json" }}
	{{/* If found: */}}

	{{/* transform.Unmasrhal will turn any json/yaml/toml string into a map (object) 
		We use it on our resource's .Content
	*/}}
	{{ $data := .Content | transform.Unmarshal }}
	{{/* `with` allow us to test the success of unmarshaling */}}
	{{ with $data }}
		{{/* Thanks to `with` our context is now the data of our file */}}
		<section>
	 		<h2>{{ .title }}</h2>
	 	<div>
	 	{{/* Use with again to make sure we've got books in there */}}
	 	{{ with .books }}
	 		{{/* Again, our context is now .books */}}
	 		{{ range . }}
				<ul>
					<li>{{ .title }}
						<p>{{ .description }}</p>
					</li>
				</ul>
	 		{{ end }}
	 	{{ end }}
		</div>
	</section>
	{{ end }}
{{ end }}

#9

Nicely commented. Thank You!!


#10

Very clear and helpful comments for a newbee like me. It allows me to better understand the process and the various steps.
I slightly modify your example to fit my project and needs and you know what It Works !
You are definitively the greatest
Thanks a lot

Nota: any chance top have some of your blog topics translated in french (my native language) ?


#11

Ah ah! Je suis francophone aussi Polaire bien cuit! :fr: :smiley: (français vivant au quebec)

Et t’as de la chance mes articles sont tous traduits par le fantastique @DirtyF sur jamstatic.fr