Issue with Gofiber framework template - go

I am in the process of learning fiber framework in GO language and having trouble figure out why the template engine is returning an error when the body section is an include. The following works as expected but when I add in another include for the "body section" it throws an error:
The Error:
html/template:fun: """ in attribute name: " ">Read Full Article\n "
This one works:
I am unable to add another template "partial" in the middle for body content, I have even tried the full design html in this section (without using includes), either way it throws the same error when loading. For some reason this sample body above works fine, but the error isn't telling me much.
This won't work:
Nor does this work:
{{template "includes/header" .}}
{{template "includes/navigation" .}}
// full html body text here (much longer than first working example)
{{template "includes/footer" .}}

I am not sure why the standard template engine had issues because the errors were not very clear, but I was able to fix the issue by switching over the jet engine. Jet seems to have better error handling. All template extensions must be switched to .jet extension and the includes change a little bit to {{include "directory/file_name" }}
// Loading Templates
engine := jet.New("./views", ".jet")
// Start Fiber
app := fiber.New(fiber.Config{
Views: engine,
})

Related

Ignore sections of a template if there is no value in Go

I'm working on a personal project to learn some more Go and hitting a snag (or potentially going about this all wrong too so there is that).
A little background first:
I'm working on a simple web app with some form fields to do some basic network tests like curl, netcat, and traceroute. I was looking to use WASM so that I could just modify the DOM with results from the Go app, but I believe due to there being a lot of syscalls, the WASM architecture doesnt support them and I couldnt compile it after a certain point or when it did it was failing anytime I ventured into some of the network pkgs. I couldn't really find another way to use javascript without abandoning Go, so I decided to go with templates.
When a form is submitted it loads a results.html that is identical to the index.html except some Go templating to print the results of the network tests. It works great has a "meh" kinda of way to simulate JS modifications and allow you to do more tests without leaving the page BUT since there are three different network tests, and only one running at one time, I get errors when it can't fill ALL the templates.
So for example
<section id="curlOutput">
<p><strong>Executed curl to {{.URL}}</strong></p>
<p>{{.Protocol}}</p>
<p>{{.Status}}</p>
<p>{{.ContentLength}}</p>
{{range $key, $val := .Headers}}
<p><strong>{{$key}}:</strong> {{$val}}</p>
{{end}}
<br/>
</section>
<section id="ncOutput">
<p><strong>Executed netcat to {{.Host}}</strong></p>
<p>{{.Result}}</p>
</section>
The issue i hit is if I want to test Netcat, Go throws errors because it can't fill the earlier templates like for curl and such. So is there a way to define in the templates that if the value doesnt exist, just continue and leave it blank? Or does every single template have to be defined and filled? Perhaps defining defaults in the templates to be empty strings somehow? Is there a better way to go about this in general?
Sorry for the length, but i felt some background would help, thanks!
You can use a data struct better suited for the task and the with template action.
type Results struct {
CURLOutput *CURLOutput
NCOutput *NCOutput
}
type CURLOutput struct {
URL string
Protocol string
Status string
ContentLength int64
Headers map[string][]string
}
type NCOutput struct {
Host string
Result string
}
{{- with .CURLOutput -}}
<section id="curlOutput">
<p><strong>Executed curl to {{.URL}}</strong></p>
<p>{{.Protocol}}</p>
<p>{{.Status}}</p>
<p>{{.ContentLength}}</p>
{{ range $key, $val := .Headers -}}
<p><strong>{{$key}}:</strong> {{$val}}</p>
{{- end }}
<br/>
</section>
{{ end }}
{{ with .NCOutput -}}
<section id="ncOutput">
<p><strong>Executed netcat to {{.Host}}</strong></p>
<p>{{.Result}}</p>
</section>
{{ end }}
https://play.golang.org/p/dOfLc_5bl8b

Golang templates won't load

I started to write a Gin application and my project tree looks like
-assets
--css
---{bootstrap}
-templates
--layouts
---footer.html
---head.html
---header.html
--book.html
-main.go
In main.go I load templates and there is no error
router.LoadHTMLGlob("./templates/layouts/*.html")
I define templates
{{ define "head" }}
<head>
//Head
</head>
{{ end }}
And I nest them
{{ define "header" }}
{{ template "head.html" . }}
//HTML
{{ end }}
But when I try to use them, I get empty output
{{ template "header" . }}
<h1>{{ .Title}}</h1>
<h3>{{ .Author.Fullname}}</h3>
[Edit] Function that executes the template:
func getBook(c *gin.Context) {
//DB stuff
var book models.Book
t, err := template.ParseFiles("templates/book.html")
if err != nil {
log.Println(err)
}
t.Execute(c.Writer, book)
}
Full-code can be found on github
router.LoadHTMLGlob and template.ParseFiles are two separate approaches to deal with templates. The template returned by ParseFiles has no knowledge of the templates loaded by LoadHTMLGlob. Once you decide to use LoadHTMLGlob you should then use c.HTML to render your templates. And the name argument to this c.HTML method would be either the name specified in a {{define "name"}} action or the base name of the template file (including the extention I believe).
So in your case you should probably do something like this:
c.HTML(http.StatusOK, "book.html", book)
More examples can be found here: https://gin-gonic.com/docs/examples/html-rendering/
Keep in mind that LoadHTMLGlob relies on template.ParseGlob which states:
When parsing multiple files with the same name in different
directories, the last one mentioned will be the one that results.
That means that if you want all of your templates to be accessible through c.HTML you need to make sure that they either have unique base names or they need to contain the {{ define "name"}} action.
Moving from the default templating system where 'everything simply worked' to Gin is a bit confusing, namely, there seem to be some naming restrictions when using files for templates. I have no idea if this is the case, but, in my setup, I had to make sure that:
The name of the template (the define keyword) needs to be the filename — at least when that's the only define in the template (I haven't tested with multiple defines) — i.e. if you're using ./templates/book.html as a template, you need to have {{ define "book.html" }} at the top of that file (this is true for templates included in other templates; I didn't experiment with blocks or other more esoteric ways to jinx templates together)
Similarly, when calling c.HTML(http.StatusOK, "book.html", book), you have to put the full name of the file containing that template (as shown!)
In other words, although the manual says otherwise, and #mkopriva confirms what the manual says, I have had a different experience: it was only I started matching the filename with the define and the c.HTML() call that I stopped getting blank pages...
Also, while running from the console (in debug mode), it was clear that my programme was 'finding' far more templates than it should — namely, almost every template was duplicated (one copy for the filename, another copy for the define, etc.). This confused not only me but the application itself...

Get {{.Host}} inside a range loop - Caddy server browse template

So I can use {{.Host}} just fine in the template file, but once inside a {{range .Items}} loop it doesn't work since it's trying to get the .Host from the .Items (array?)thing..
I get this as an error
template: listing:41:46: executing "listing" at <.Host>: can't evaluate field Host in type browse.FileInfo
I've never used Go before, I've tried reading the text template documentation page but it's all rather confusing.
ooooh, nevermind guys, I knew it was a simple fix.
{{$.Host}}
Just add the $, then you'll be using the global context again, instead of the context inside of the range loop.
Source, thanks HUGO for the clear documentation.
{{range}} changes the pipeline (the dot, .) to the current Items. You can use {{$.Host}} which will refer to the "top-level" Host.
{{$.Host}}
golang template.

Is it possible to have nested templates in Go using the standard library?

How do I get nested templates like Jinja has in the python runtime. TBC what I mean is how do I have a bunch of templates inherit from a base templates, just filing in blocks of the base templates, like Jinja/django-templates does. Is it possible using just html/template in the standard library.
If that is not a possibility, what are my alternatives. Mustache seems to be an option but would I then be missing out on those nice subtle features of html/template like the context sensitive escaping etc.? What other alternatives are ther?
(Environment: Google App Engin, Go runtime v1, Dev - Mac OSx lion)
Thanks for reading.
Yes it is possible. A html.Template is actually a set of template files. If you execute a defined block in this set, it has access to all the other blocks defined in this set.
If you create a map of such template sets on your own, you have basically the same flexibility that Jinja / Django offers. The only difference is that the html/template package has no direct access to the file system, so you have to parse and compose the templates on your own.
Consider the following example with two different pages ("index.html" and "other.html") that both inherit from "base.html":
// Content of base.html:
{{define "base"}}<html>
<head>{{template "head" .}}</head>
<body>{{template "body" .}}</body>
</html>{{end}}
// Content of index.html:
{{define "head"}}<title>index</title>{{end}}
{{define "body"}}index{{end}}
// Content of other.html:
{{define "head"}}<title>other</title>{{end}}
{{define "body"}}other{{end}}
And the following map of template sets:
tmpl := make(map[string]*template.Template)
tmpl["index.html"] = template.Must(template.ParseFiles("index.html", "base.html"))
tmpl["other.html"] = template.Must(template.ParseFiles("other.html", "base.html"))
You can now render your "index.html" page by calling
tmpl["index.html"].Execute("base", data)
and you can render your "other.html" page by calling
tmpl["other.html"].Execute("base", data)
With some tricks (e.g. a consistent naming convention of your template files), it's even possible to generate the tmpl map automatically.
note, when you execute your base template, you must pass values down to the child templates, here I simply pass ".", so that everything is passed down.
template one displays {{.}}
{{define "base"}}
<html>
<div class="container">
{{.}}
{{template "content" .}}
</div>
</body>
</html>
{{end}}
template two displays {{.domains}} that's passed into the parent.
{{define "content"}}
{{.domains}}
{{end}}
Note, if we used {{template "content"}} instead of {{template "content" .}}, .domains wouldn't be accessible from the content template.
DomainsData := make(map[string]interface{})
DomainsData["domains"] = domains.Domains
if err := groupsTemplate.ExecuteTemplate(w, "base", DomainsData); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
having worked with other template packages, now a days I mostly work with standard html/template package, I guess I was naive to not appreciate the simplicity it provides and other goodies. I use a very similar approach to accepted answer with following changes
you don't need to wrap your layouts with additional base template, a template block is created for every parsed file so in this case it is redundant, I also like to use the block action provided in new version of go, which allows you to have default block content in case you don't provide one in child templates
// base.html
<head>{{block "head" .}} Default Title {{end}}</head>
<body>{{block "body" .}} default body {{end}}</body>
and you page templates can be the same as
// Content of index.html:
{{define "head"}}<title>index</title>{{end}}
{{define "body"}}index{{end}}
// Content of other.html:
{{define "head"}}<title>other</title>{{end}}
{{define "body"}}other{{end}}
now to execute the templates you need to call it like so
tmpl["index.html"].ExecuteTemplate(os.Stdout, "base.html", data)
Use Pongo, which is a super-set of Go Templates that supports the {{extends}} and {{block}} tags for template inheritance, just like Django.
I've been coming back to this answer for days, finally bit the bullet and wrote a small abstraction layer / pre processor for this. It basically:
Adds the 'extends' keyword to templates.
Allows overriding 'define' calls (thus default values for greggory are possible)
Allows non defined 'template' calls, they just give an empty string
Sets the default value of . in 'template' calls to . of the parent
https://github.com/daemonl/go_sweetpl

ClientGlobalContext.js.aspx broken in Dynamics 2011?

I am trying to implement a custom web resource using jquery/ajax and odata. I ran into trouble and eventually found that when I call:
var serverUrl = context.getServerUrl();
The code throws exceptions.
However, when I change serverUrl to the literal url, it works. I then found forum posts that said I should verify my .aspx page manually by going to https://[org url]//WebResources/ClientGlobalContext.js.aspx to verify that it is working. When I did that I received a warning page:
The XML page cannot be displayed
Cannot view XML input using style sheet. Please correct the error and then click the Refresh button, or try again later.
--------------------------------------------------------------------------------
Invalid at the top level of the document. Error processing resource 'https://[org url]//WebResources/Clien...
document.write('<script type="text/javascript" src="'+'\x26\x2347\x3b_common\x26\x2347\x3bglobal.ashx\x26\x2363\x3bver\x2...
What the heck does that mean?
Hard to tell outside of context (pun not intended) of your code, but why aren't you doing this?
var serverUrl = Xrm.Page.context.getServerUrl();
(Presumably, because you have defined your own context var?)
Also, this method is deprecated as of Rollup 12, see here: http://msdn.microsoft.com/en-us/library/d7d0b052-abca-4f81-9b86-0b9dc5e62a66. You can now use getClientUrl instead.
I now it is late but hope this will be useful for other people who will face this problem.
Until nowadays even with R15 there are two available ClientGlobalContext.js.aspx
https://[org url]/WebResources/ClientGlobalContext.js.aspx (the bad one)
https://[org url]/[organization name]/[publication id]/WebResources/ClientGlobalContext.js.aspx (The good one)
I don't know why exist 1. but it causes many issues like:
It could not be published or hold information (Your case #Steve).
In a deployment with multiple organizations, seems it saves info only for the last organization deployed causing that methods under Xrm.Page.context. will return info from a fixed organization. Actually each method that underground uses these constants included in ClientGlobalContext.js.aspx: USER_GUID, ORG_LANGUAGE_CODE, ORG_UNIQUE_NAME, SERVER_URL, USER_LANGUAGE_CODE, USER_ROLES, CRM2007_WEBSERVICE_NS, CRM2007_CORETYPES_NS, AUTHENTICATION_TYPE, CURRENT_THEME_TYPE, CURRENT_WEB_THEME, IS_OUTLOOK_CLIENT, IS_OUTLOOK_LAPTOP_CLIENT, IS_OUTLOOK_14_CLIENT, IS_ONLINE, LOCID_UNRECOGNIZE_DOTC, EDIT_PRELOAD, WEB_SERVER_HOST, WEB_SERVER_PORT, IS_PATHBASEDURLS, LOCID_UNRECOGNIZE_DOTC, EDIT_PRELOAD, WEB_RESOURCE_ORG_VERSION_NUMBER, YAMMER_IS_INSTALLED, YAMMER_IS_CONFIGURED_FOR_ORG, YAMMER_APP_ID, YAMMER_NETWORK_NAME, YAMMER_GROUP_ID, YAMMER_TOKEN_EXPIRED, YAMMER_IS_CONFIGURED_FOR_USER, YAMMER_HAS_CONFIGURE_PRIVILEGE, YAMMER_POST_METHOD. For instance method Xrm.Page.context.getUserId() is implemented as return window.USER_GUID;
To be sure that your URL is the correct just follow the link posted by #Chris

Resources