Learning to Go: Part 6 - Rendering Results

Search for a command to run...

No comments yet. Be the first to comment.
Learn to write Go code by creating a basic web app that will provide a front-end for a public API
Oh hi! This is a multi-part tutorial series, please make sure you reads the posts in order! You can find the list at the bottom of the page. We’ve come a long way, from a simple Hello World to a fully functional dialog search engine for Star Trek: Th...
Next up in my quest to Learn All The Things™ on the CNCF graduated projects page, we’re going to take a look at a lesser known Argo project: Argo Rollouts. In a nutshell, Argo Rollouts are a drop-in replacement for the Deployment object that provide ...

Continuing my efforts to explore and Learn All The Things™ on the CNCF graduated projects page, today I’m going to take a look at Argo Workflows, which is one of 4 tools in the Argo project overall (see my previous post on ArgoCD). Argo Workflows is ...

In my never-ending quest to Learn All The Things™, I’ve decided to take a tour through the Cloud Native Computing Foundation’s graduated projects page. I’m doing this for a few different reasons: Lea

This is the tenth post in a series exploring the features of GKE Enterprise, formerly known as Anthos. GKE Enterprise is an additional subscription service for GKE that adds configuration and policy management, service mesh and other features to supp...

This is the ninth post in a series exploring the features of GKE Enterprise, formerly known as Anthos. GKE Enterprise is an additional subscription service for GKE that adds configuration and policy management, service mesh and other features to supp...

Oh hi! This is a multi-part tutorial series, please make sure you reads the posts in order! You can find the list at the bottom of the page.
Okay, to recap: We’ve successfully queried the API and stored the results in a struct. So how do we actually use this data to render a results page for our user? You’d think this would be one of the trickier stages of our tutorial, but it’s actually very simple.
As we saw in the previous step, we’re actually passing the entire dialog object - a slice of struct objects containing our search results - into our templating engine. All we need to do is update the template to display some results. Let’s start with the stylesheet first. Add the following on the end of style.css:
.container {
width: 100%;
max-width: 720px;
margin: 0 auto;
padding: 80px 20px 40px;
}
.search-results {
list-style: none;
}
.dialog {
display: flex;
align-items: flex-start;
margin-bottom: 30px;
border: 1px solid var(--light-grey);
padding: 15px;
border-radius: 4px;
justify-content: space-between;
}
.title {
margin-bottom: 15px;
}
.description {
color: var(--dark-grey);
margin-bottom: 15px;
}
Next, we’ll add a block to our index.html page that renders our results in a list. This should go after </header> but before </main>:
<section class="container">
<ul class="search-results">
{{ range . }}
<li class="dialog">
<div>
<h3 class="title">Episode: {{ .Episodename }}</h3>
<p class="description">Line: "{{ .Text }}"</p>
</div>
</li>
{{ end }}
</ul>
</section>
Here we are using some more nifty features of Go templating. Using range we can iterate through all of the objects in the dialog variable that we passed to the template. Note that, as dialog is the object we passed, we simply refer to it as . (if we wanted to loop over an object inside dialog we could have used .OtherObject).
Once inside the {{ range }} loop, we can access each field of the struct, as you can see when we call {{ .Episodename }} and {{ .Text }}.
Save your changes, and start your app serving again with go run main.go. Now try a search term again and look! Results!

This is great, but we actually have a lot more info being passed to our template that we can display. Update index.html again to this:
<section class="container">
<ul class="search-results">
{{ range . }}
<li class="dialog">
<div>
<h3 class="title">Episode: {{ .Episodename }}</h3>
<p class="description">{{ .Who }}: <i>"{{ .Text }}"</i></p>
<p>Act {{ .Act }} Scene {{ .Scenenumber }}</p>
<p>Season {{ .Season }} Episode {{ .Episode }}</p>
</div>
</li>
{{ end }}
</ul>
</section>
Save your changes and run go run main.go again. Try a different search this time. I’m searching for “Lanel”, the alien doctor played by Bebe Neuwirth (Frasier’s ex-wife!):

Now we get much more information rendered for our user. But at this point you may have noticed something about the API we’re querying. It will sometimes return stage direction as well as dialog. That’s why in the first result, the speaker appears to be “NA”. Thankfully, Go templates also contain some basic functions, like if that we can use to change the way we display results based on the results themselves.
Change the <p class="description">...</p> line in index.html to the following:
{{ if eq .Texttype "speech" }}
<p class="description">{{ .Who }}: <i>"{{ .Text }}"</i></p>
{{ else }}
<p class="description">{{ .Text }}</p>
{{ end }}
One of the fields in our struct is Texttype which will contain the word “speech” if it’s a spoken word of dialog. Using if and eq we can check if this is true, in which case we output who is speaking, and the line of dialog italicised. Then we use an else to render everything else without the speaker, because there won’t be one.
While we’re here, let’s add something to the .description definition in our style.css to make this look a bit more like a TV script:
font-family: "Courier New", Courier, monospace;
Now save everything and run go run main.go again.

Looking good!
In this part we successfully used fields from our struct to render meaningful results to our users, and we used logical functions inside the template to change the formatting of results on a case-by-case basis. In part 7 we’ll add some final touches, including images, to make our app look really polished.
Here are the complete updated gists if you need to check them against yours: index.html and styles.css.