How to create multiple views of same content?

My site uses the tags taxonomy. And has urls such as:
tags/north
tags/south
… etc.
These display a list of physical locations using a list.html template. That works.

I also want a link to an alternate view of this same data which will show google maps of the locations (not separate maps for each location, but a single map that shows all the locations). I already know how to display the items on a google map in hugo but how do I structure the content such that it can show either a list view or a map view?

I imagine the user will click a tag and be presented with the normal list view, and then can click a “view map” link which will open a new page with the same content rendered on a map. And likewise from the map view they can click a link “view list” to view the content rendered as a list.

I can make a new template that will render the items on a google map but how do I create a link with this alternate template view?

I don’t fully understand your layout concept. Sounds interesting but complex. So I’m not sure, if the following hint will help you:

Hugo lets you create as many list item views as you like. You can call them with the function .Render.

Hi, have you looked at output formats? You could create an output format for the map, then make sure your term template uses it on top of the default HTML one, and find the link easily enough with (.OutputFormats.Get "map").RelPermalink

Unfortunately I don’t think you can have Hugo create it at a beautiful URL like /tags/north/map/, it will have to be /tags/north/map.html or something… but I may be wrong.

1 Like

I would be tempted to render the list and the map on the same page, and use JS to toggle between the two with a button.

layouts/tags/term.html

<div id="list">
  <button onclick="showMap();">Show map</button>
  {{ range .Pages }}
    <h2><a href="{{ .RelPermalink }}">{{ .Title }}</a></h2>
  {{ end }}
</div>
<div id="map" style="display: none;">
  <button onclick="showList();">Show list</button>
  GOOGLE MAP CODE HERE
</div>

<script>
  function showMap() {
    document.getElementById('list').style.display = 'none';
    document.getElementById('map').style.display = 'block';
  }
  function showList() {
    document.getElementById('list').style.display = 'block';
    document.getElementById('map').style.display = 'none';
  }
</script>
1 Like

Interesting I did come across output formats in my search but I assumed they were for serving json, xml, etc. So you can define an arbitrary output format that is also html? Will the Content-Type header sent still be “text/html”?

Yes just use text/html as mediaType

I was thinking the same and I may ultimately go down this route, although I am still curious to know how to get same source content rendered by two different templates at different urls although sounds like output formats may do that

I like this although having to have a url end in .html may bother me enough to make me use the javascript solution instead

There’s another, advanced approach that uses resources.FromString to publish pages without having a stub in content.

Here’s a simple example:

git clone --single-branch -b hugo-forum-topic-40172 https://github.com/jmooring/hugo-testing hugo-forum-topic-40172
cd hugo-forum-topic-40172
hugo server

One minor drawback is that you will have restart hugo server after making changes to the content or template.

2 Likes

That’s pretty interesting… what will the url be? I don’t understand exactly what this line does… Why is it index.html?

{{ $targetPath := path.Join .RelPermalink "map" "index.html" }}

/tags/north/map?

Yes, the URLs will be:

  • http://localhost:1313/tags/north/
  • http://localhost:1313/tags/north/map/

That’s what web servers (e.g. Apache) look for when you browse to a directory.

With RSS and sitemap disabled, this is what hugo writes to the public directory:

public/
├── location/
│   ├── location-1/
│   │   └── index.html
│   ├── location-2/
│   │   └── index.html
│   └── index.html
├── tags/
│   ├── north/
│   │   ├── map/
│   │   │   └── index.html
│   │   └── index.html
│   ├── south/
│   │   ├── map/
│   │   │   └── index.html
│   │   └── index.html
│   └── index.html
└── index.html

Ah yes still trying to understand hugo syntax… Could you also do?

{{ $targetPath := .RelPermalink "map/index.html" }}

Does this not work or is inferior?

You need to join the strings with path.Join, print, printf, or add.

{{ $page := partial "map.html" $ctx }}

I noticed in the map.html partial you have the complete page layout (e.g. doctype, html etc.). Is it possible to use the existing main site layout without recreating it, and if so how (can I use {{ define "main" }})? I don’t know if that was just for simplicity in your demo project.

I haven’t found a way to do it. You can certainly map layouts/_default/baseof.html to layouts/partials/foo.html, but the base/block functionality doesn’t work (as expected).

What do you mean by this?

It’s irrelevant since you can’t use the base/block functionality.

But what I meant was, if you want to access baseof.html in a partial call, it has to exist in the layouts/partials directory. And you can do that without copying by mounting the file via site config. Something like:

[[module.mounts]]  # You must include the default mount
source = 'layouts'
target = 'layouts'

[[module.mounts]]
source = 'layouts/_default/baseof.html'
target = 'layouts/partials/foo.html'
1 Like

Regarding the JS show/hide approach… you could also use a query string parameter to toggle the action. That way you could have two URLS:

  • http://localhost:1313/tags/north
  • http://localhost:1313/tags/north?view=map
1 Like

Does this imply that you could have /tags/north/ and /tags/north/map?

https://gohugo.io/templates/output-formats/

  • A page can be output in as many output formats as you want, and you can have an infinite amount of output formats defined as long as they resolve to a unique path on the file system. In the above table, the best example of this is AMP vs. HTML. AMP has the value amp for Path so it doesn’t overwrite the HTML version; e.g. we can now have both /index.html and /amp/index.html.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.