How to test if a Go template block is defined? - go

I'm using Go 1.19 with the built-in HTML template engine. Is there a way to test if a block is defined in a particular template file?
Specifically, I want to implement optional header entries in the Go HTML template.
I have a general layout template that includes a content template when rendered.
I want to implement as below...
Currently, the <meta name="description" content="{{block "description" .}}{{end}}"> result in an empty description tag. I'd like to not have the tag at all if there is nothing in it.
Any ideas?
layout.gohtml (simplified)[updated]
<html>
<head>
<title>{{block "title" .}}The Title{{end}}</title>
{{if .renderDescription}}
<meta name="description" content="{{template "description"}}">
{{end}
</head>
<body>
<header></header>
{{template "content" .}}
<footer></footer>
</body>
</html>
content1.gohtml
{{define "title"}}The 2hO Network{{end}}
{{define "description"}}An options description{{end}}
{{define "content"}}
Vestibulum ante ipsum primis in faucibus...
{{end}}
content2.gohtml
{{define "title"}}The 2hO Network{{end}}
{{define "content"}}
Vestibulum ante ipsum primis in faucibus...
{{end}}

Templates are designed to be statically analyzable. This means if you don't have a description template, you'll get an error when parsing the templates.
Instead use an {{if}} action to check if the description template needs to be rendered. The description template maybe empty.
For example:
{{if .renderDescription}}
{{template "description"}}
{{end}}
{{define "description"}}description content{{end}}
If you have to check the .renderDescription in many places, you may also move the check (the {{if}} action) into the template, so you can unconditionally use {{template}} (but you still have to provide a pipeline that contains the condition):
{{template "description" .}}
{{define "description"}}
{{if .renderDescription}}
description content
{{end}}
{{end}}
Notes:
The {{block}} action is not to include a template, it is to define and include a template. To include a template defined elsewhere, use {{template}}.
You also have to change your template structuring. Instead of having a "frame" template embedding a "content", define "header" and "footer" templates, and have each page have its own template, which include "header", the content and "footer".

Related

golang html/template define not working as intended

the html/template module has a define/template feature that im trying to use to make it easier to change only one file that contains the global base of my website but its not working as intended.
base.html:
{{define "base"}}
<!DOCTYPE html>
<html lang="en">
<body>
{{template "content"}}
</body>
</html>
{{end}}
index.html:
{{template "base"}}
{{define "content"}}
I'm page 1
{{end}}
blog.html:
{{template "base"}}
{{define "content"}}
I'm page 2
{{end}}
I expect to get I'm page 1 when i call index.html and I'm page 2 when i call blog.html but with both files i get I'm page 1 as the output. (i don't know what a dot at the end of template does but all combinations of that don't work aswell).
You cannot redefine and replace templates like that. Do the reverse: define index.html and blog.html as page1 and page2 respectively, import common header.html and footer.html into those.

How do I extend views properly in laravel 5?

I have a project which has 2 login forms, one for consumers and one for creators.
Both have different "post-login" areas.
But the view should look pretty similar, so I thought why not DRY-it™.
QUESTION: Here is my solution, but I am sure there is a more elegant solution, please enlighten me if there is.
login.blade.php (master template)
#extends('layout.app')
#section('styles')
{{ Html::style('css/login.css') }} // This also looks deprecated, how do I have a specific css only for this page?
#stop
#section('content')
<div class="container">
<form class="form-signin" action="{{ $loginAction }}"> //smells really bad
<h2 class="form-signin-heading">Login {{ $loginTitle }}</h2>
...
#endsection
login_consumer.blade.php
#extends('layout.login', [
'loginTitle' => 'Consumer',
'loginAction' => 'login_consumers'
])
login_creator.blade.php
#extends('layout.login', [
'loginTitle' => 'Creators',
'loginAction' => 'login_creators'
])
Thanks in advance
Common layout containing header, body content and footer
are app.blade.php having #yields('') directive within allows you to inherit it as well as let you extend with new content through #extends('') directive. Also, you can append in master stylesheet through #show and #parent blade directive as below.
<!-- Stored in resources/views/layouts/app.blade.php -->
<html>
<head>
<title>App Name - #yield('title')</title>
#section('stylesheets')
<link rel="stylesheet" type="text/css" href="style.css"> <!-- this is master stylesheet -->
#show
</head>
<body>
<div class="container">
#yield('content')
</div>
</body>
</html>
Extending a layout
<!-- Stored in resources/views/login.blade.php -->
#extends('layouts.app')
#section('title', 'Page Title')
#section('stylesheets')
#parent
<link rel="stylesheet" type="text/css" href="login.css">
#endsection
#section('content')
<p>This is my body content.</p>
#endsection
Now, explaining your second part of your question. Above case was about a common layout, but this case you are trying to achieve common body content so there's Components & Slots for that. Separate your common body content as a component and pass variable as a slot. This came from Laravel 5.4. Previously, it was called partials which was used through #include('') directive.
https://laravel.com/docs/5.5/blade#components-and-slots

Parse Custom Variables Through Templates in Golang

Is it possible for me to set a variable in a template file {{$title := "Login"}} then parse it through to another file included using {{template "header" .}}?
An example of what I'm attempting:
header.tmpl
{{define "header"}}
<title>{{.title}}</title>
{{end}}
login.tmpl
{{define "login"}}
<html>
<head>
{{$title := "Login"}}
{{template "header" .}}
</head>
<body>
Login Body!
</body>
</html>
{{end}}
How can I parse this custom $title variable I made through to my header template?
As #zzn said, it's not possible to refer to a variable in one template from a different one.
One way to achieve what you want is to define a template – that will pass through from one template to another.
header.html
{{define "header"}}
<title>{{template "title"}}</title>
{{end}}
login.html
{{define "title"}}Login{{end}}
{{define "login"}}
<html>
<head>
{{template "header" .}}
</head>
<body>
Login Body!
</body>
</html>
{{end}}
You could also pass through the title as the pipeline when you invoke the "header" template ({{template header $title}} or even {{template header "index"}}), but that will prevent you passing in anything else to that template.
no, it's impossible parse variable through to another file.
according to this:
A variable's scope extends to the "end" action of the control structure ("if", "with", or "range") in which it is declared, or to the end of the template if there is no such control structure. A template invocation does not inherit variables from the point of its invocation.

Golang multiple template caching

Is it possible to render multiple html templates with the same name in golang. The reason is, that i want to make a layout and reuse it for multiple views. For example:
{{define "MainLayout"}}
<html>
<head>
<title>{{.Title}}</title>
</head>
<body>
<div>{{template "Content" .}}</div>
</body>
</html>
{{end}}
Content could be different templates, that all are defined by {{define "Content"}}
I believe elithrar has what you are looking for, but unfortunately it's not currently supported. The typical way of handling this problem would be defining your header and footer in their own templates and doing the inverse of your approach. And you can pass the struct being given to the template parser into those templates to render your pages.
{{define "header"}}
<html>...
{{end}}
{{define "footer"}}
...</html>
{{end}}
{{define "Content"}}
{{template "header" .}}
HTML
{{template "footer" .}}
{{end}}
How are you parsing your templates? You can't have two templates with the same name in the same template tree. However, you could create a custom parsing function that will only add one template named "Content" to your template tree.
Example: https://play.golang.org/p/35X3i_jPzS

Variable in template's included template

I am trying to put values into a "header" template, like the title and navigation links but can't access the variables that I sent to the main template from the included one.
Rendering the template:
...
templateName := "index"
args := map[string]string{
"Title": "Main Page",
"Body": "This is the content",
}
PageTemplates.ExecuteTemplate(w, templateName+".html", args)
...
index.html template:
{{template "header"}} <-- Including the "header.html" template
{{.Body}} <-- Variable that works
{{template "footer"}} <-- Does not matter!
header.html template:
{{define "header"}}
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{.Title}}</title> <-- Variable empty :(
</head>
<body>
{{end}}
Apparently, it won't work that way.
Maybe there's a way I could parse/get the template and put my variables into it without putting the whole header file into code? Then I could just send that template as a variable to my main template. But that does not seem like it would be the best way to do it.
You can pass the context to the template when you call it. In your example, changing {{template "header"}} to {{template "header" .}} should be sufficient.
The relevant parts from the official docs:
{{template "name"}}
The template with the specified name is executed with nil data.
{{template "name" pipeline}}
The template with the specified name is executed with dot set to the value of the pipeline.
PS: It is not relevant to the question, but you should also remove the newline between {{define "header"}} and <!DOCTYPE html>, so that the doctype is really the first thing in your template.

Resources