Golang template does not render html - go

I created a subfolder called 'views' in my web root directory. Within the View folder, I have the static folder which contains the css and js files.
The html pages are rendered when I have the html files in the web root. However they do not render when placed within the views folder. I am using template.ParseGlob to parse the file and ExecuteTemplate to render.
package main
import (
"html/template"
"net/http"
"github.com/gorilla/mux"
)
var router = mux.NewRouter()
var tmpl *template.Template
func init() {
tmpl = template.Must(template.ParseGlob("view/*.html"))
}
func indexPage(w http.ResponseWriter, r *http.Request) {
err := tmpl.ExecuteTemplate(w, "signin", nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func main() {
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("view/"))))
router.HandleFunc("/", indexPage)
http.ListenAndServe(":8091", router)
}
HTML files: Have defined the header and footer in index.html which I refernce in the signin.html file
{{ define "header"}}
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>User Sign in</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="/static/css/main.css">
<script src="/static/js/vendor/modernizr-2.8.3-respond-1.4.2.min.js"></script>
</head>
<body>
{{end}}
{{define "footer"}}
<footer class="panel-footer"><p>© Company 2016</p></footer>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.11.2.min.js"><\/script>')</script>
<script src="/static/js/vendor/bootstrap.min.js"></script>
<script src="/static/js/main.js"></script>
<!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
<script>
(function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]=
function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date;
e=o.createElement(i);r=o.getElementsByTagName(i)[0];
e.src='//www.google-analytics.com/analytics.js';
r.parentNode.insertBefore(e,r)}(window,document,'script','ga'));
ga('create','UA-XXXXX-X','auto');ga('send','pageview');
</script>
</body>
</html>
{{end}}
signin.html file:
{{define "signin"}}
{{template "header" .}}
<h1 class="alert alert-info">Login</h1>
<div class="container">
{{with .Errors.message}}
<div class="alert alert-danger">
{{.}}
</div>
{{end}}
<form method="POST" action="/">
<label class="form-control" for="uname">User Name</label>
<input class="form-control" type="text" id="uname" name="uname">
<label class="form-control" for="password">Password</label>
<input class="form-control" type="password" id="password" name="password">
<button class="btn btn-info" type="submit">Submit</button>
</form>
{{template "footer" .}}
{{end}}
Why is it that this doesn't work when I place the html files in the sub-directory 'views'. The only thing that changes is the argument to parseGlob.

I believe all you need to do is remove this line:
router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("view/"))))
Works for me. Though you need to clean up your html a bit too - I see at least a missing </div>.
Templates are processed on the server and do not need to be served over internet. At the same time this route entry conflicts with the following one (indexPage) which defines another handler for the same route entry ("/"). So when you open it in a browser, server just send template files over internet. While indexPage handler is never called as directory handler is matched first.
Also you talking about "views" folder, but you code says "view" (without 's' at the end). Could be another simple reason.

Related

I can't show an html page

I have to develop a project for college using Spring. I started watching some tutorials and I can't show an html page. I do the same but it returns only one string.
I'm using visual studio code.
Controller:
package com.example.springteste.controllers;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class ProductController {
#GetMapping("/formulario")
public String formulario()
{
return "form";
}
}
My view is just inside templates
View:
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<main>
<section id="sectionProduct">
<div>
<div id="sectionProduct-title">
<h1>
Título
</h1>
</div>
<div id="sectionProduct-form">
<form action="">
<div class="sectionProduct-form-inputLabel">
<input type="text" id="title" name="title">
<label for="title">
Título
</label>
</div>
</form>
</div>
</div>
</section>
</main>
</body>
</html>
I believe something is missing. I am a beginner in java and spring
If you want to return a view name from the controller method handler - you have to use #Controller annotation. Also make sure you put your views into the correct directory, according to your view resolver configuration.
About #RestController - as the name suggests, it shall be used in case of REST style controllers i.e. handler methods shall return the JSON/XML response directly to the client rather using view resolvers.
In your case the handler method will return "form" to the client.

golang renderer.HTML not picking javascript file from inside the template

Trying to publish a login page using "github.com/thedevsaddam/renderer" package renderer . Not able to call the .js file from inside the template. When tried inlining javascript it worked fine, but not able to load the .js file.
my file structure is
Project
|
+-main.go
|
+-handlers
| |
| +- routes.go
| |
| +- login.go
+-views
| |
| +- _login.html
| +- login.js
main.go
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/higuestssg/handlers"
)
func main() {
router := mux.NewRouter().StrictSlash(true)
// This will serve files under http://localhost:8000/static/<filename>
router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("views/"))))
portalRouter := router.PathPrefix("/portal").Subrouter()
handlers.HandleRoutes(portalRouter)
fmt.Println("listening at localhost:10001")
log.Fatal(http.ListenAndServe(":10001", router))
}
routes.go
package handlers
import (
//"net/http"
"github.com/gorilla/mux"
)
func HandleRoutes(r *mux.Router){
r.HandleFunc("/login", loginHandler)
r.HandleFunc("/healthTest", healthTestHandler)
}
login.go
package handlers
import (
"fmt"
"net/http"
//"github.com/gorilla/mux"
"github.com/thedevsaddam/renderer"
)
var rnd *renderer.Render
func init() {
opts := renderer.Options{
ParseGlobPattern: "./views/*.html",
}
rnd = renderer.New(opts)
}
// loginHandler renders login page
func loginHandler(w http.ResponseWriter, r *http.Request) {
data := struct {
Val1 string
Val2 string
}{
"test100",
"test2",
}
fmt.Println("login page hit")
rnd.HTML(w, http.StatusOK, "_login", data)
}
_login.html
{{ define "_login" }}
<!--
https://medium.com/#thedevsaddam/easy-way-to-render-html-in-go-34575f858026
-->
<!DOCTYPE html>
<html lang="en">
<!-- Bootstrap import CSS-->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<body>
<div class="container">
<div class="starter-template jumbotron text-center">
<h1>HI GUEST</h1>
<div class="col-sm-4">
<p class="lead">Welcome to <strong>HI_GUEST --ssg</strong> page</p>
</div>
</div>
</div><!-- /.container -->
<div class="row">
<div class="col-sm-4"><p class="lead" id="idtest1">Test1</p></div>
<div class="col-sm-4"><p class="lead">Test2</p></div>
<div class="col-sm-4"><p class="lead"><button type="button" class="btn btn-info btn-lg" name="btn_ip" id="btn_id" onclick="myFunction()">{{.Val1}}</button></p></div>
</div>
</body>
<script type='text/javascript' src='login.js'></script>
</html>
{{ end }}
login.js
function myFunction()
{
alert("Hello");
}
$(document).ready(function () {
alert("Hello");
});
When checked in chrome using viewSource, when clicked on login.js its showing 404 not found
updated _login.html , its working fine with #mkopriva suggestion
{{ define "_login" }}
<!--
https://medium.com/#thedevsaddam/easy-way-to-render-html-in-go-34575f858026
-->
<!DOCTYPE html>
<html lang="en">
<!-- Bootstrap import CSS-->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<body>
<div class="container">
<div class="starter-template jumbotron text-center">
<h1>HI GUEST</h1>
<div class="col-sm-4">
<p class="lead">Welcome to <strong>HI_GUEST --ssg</strong> page</p>
</div>
</div>
</div><!-- /.container -->
<div class="row">
<div class="col-sm-4"><p class="lead" id="idtest1">Test1</p></div>
<div class="col-sm-4"><p class="lead">Test2</p></div>
<div class="col-sm-4"><p class="lead"><button type="button" class="btn btn-info btn-lg" name="btn_ip" id="btn_id" onclick="myFunction()">{{.Val1}}</button></p></div>
</div>
</body>
<script type='text/javascript' src='/static/login.js'></script>
</html>
{{ end }}

Does gin-gonic support get request?

I am new in gin-gonic framework and i have been trying to read the values from the inputs that i added in a get request from html but i have not been able to read the values that i wrote.
When i submit the request the browser sends this url :
http://localhost:3000/backend?name1=value1&name2=value2&name3=value3
I have been looking in the internet where gin-gonic uses this url type but i have only found that it uses url like this one
http://localhost:3000/backend/value1
html code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form method="GET" action="/backend">
<input id="store" name="name1" type="text">
<input id="razon" name="name2" type="text">
<input id="total" name="name3" type="text">
<input type="submit" value="submit">
</form>
</body>
</html>
golang code:
package main
import(
"net/http"
"fmt"
"github.com/gin-gonic/contrib/static"
"github.com/gin-gonic/gin"
)
func main(){
router := gin.Default()
router.Use(static.Serve("/",static.LocalFile("./views",true)))
router.GET("/backend",func(c *gin.Context){
fmt.Println(c.Param("name1"))
c.JSON(http.StatusOK, gin.H{
"name1" : c.Param("name1"),
})
})
router.Run(":3000")
}
Actual result:
{"name1":""}
Expected result:
{"name1":"value1"}
The function you are looking for is not Param(), it's Query().
https://github.com/gin-gonic/gin#querystring-parameters

can we call a ftl macro from javascript function

<html lang="en">
<head>
<meta charset="UTF-8">
<title> Java, Spring Boot, FreeMarker</title>
<link href="/css/main.css" rel="stylesheet">
</head>
<script>
function myFunction() {
<#test/>
}
</script>
<body>
<h2>Java, Spring Boot, FreeMarker</h2>
<form action="/search" method="post">
Search : <input type="text" name="firstName" onkeyup="myFunction()" id = "fname">
<input type="submit" value="Submit">
</form>
<div style="background-color:lightblue">
<#macro test>
<#list empList as emp>
<div id="emp-data">
<ul>
<li>${emp}</li>
</ul>
</#list>
</div>
</#macro>
<script src="/js/main.js"></script>
</div>
</body>
When I run this code I am getting some errors on the browser console:
(index):60 Uncaught ReferenceError: myFunction is not defined at HTMLInputElement.onkeyup ((index):60) onkeyup # (index):60 – PCS 1 hour ago
Is it possible in FreeMarker to do something like that?
In a sense you can... but it doesn't do what you apparently believe it does. First all FreeMarker instructions, like <#test/>, are resolved on the server, then later the resulting output runs in the browser. So as far as the browser sees, function myFunction() { ... } contains HTML div-s directly in inside the { ... }, which is invalid JavaScript.

Thymeleaf + spring dynamic replace

Is it possible to create a dynamic replace in Thymeleaf?
I have the following controller:
#Controller
public class LoginController {
#RequestMapping("/login")
public String getLogin(Model model){
model.addAttribute("template","login");
return "index";
}
}
And the following view:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" >
<head></head>
<body>
<div th:replace="fragments/${template} :: ${template}"></div>
</body>
</html>
And i'm getting the following error:
Error resolving template "fragments/${template}", template might not exist or might not be accessible by any of the configured Template Resolvers
UPDATE
I tried to preprocess my variables like this:
<div th:replace="fragments/${__#{${template}}__} :: ${__#{${template}}__}"></div>
How ever now ${template} is getting replaced with login i have the following error now:
Exception evaluating SpringEL expression: "??login_en_US??"
Although Joe Essey's solution is working as well i solved with following code:
<div th:replace="#{'fragments/' + ${template}} :: ${template}"></div>
I believe the appropriate method to manage this behavior in thymeleaf is to use layout:fragment tags. Please correct me if I'm wrong. Here is a simple example of my layout page, and the login page which is 'dynamically' loaded:
layout.html
<html xmlns:layout="http://www.w3.org/1999/xhtml" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">Layout</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
</head>
<body>
<div>
<div class="app-container">
<div th:fragment="content">
</div>
</div>
</div>
<div th:fragment="script"></div>
</body>
</html>
Then, when login gets loaded, it replaces the th:fragment div with the associated div in the html view which matches the string returned by the controller method, in this case login.html:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.w3.org/1999/xhtml"
layout:decorator="layout">
<head>
<title>Login</title>
</head>
<body>
<div th:fragment="content">
<form th:action="#{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</div>
</body>
</html>
Now, if you want to load another fragment conditionally, the approach I take is to add replace tags with th:if cases. Here's an example of a Form that displays different questions based on an attribute of the current user:
<div th:if="${foo.type)} == 'type_1'">
<div th:replace="fragments/custom-questions :: type-1-checkboxes"></div>
</div>
<div th:if="${foo.type} == 'type_2'">
<div th:replace="fragments/custom-questions :: type-2-checkboxes"></div>
</div>
Then the associated div gets loaded from the file custom-questions.html:
<div th:fragment="type-1-checkboxes">
//stuff
</div>
<div th:fragment="type-2-checkboxes">
//stuff
</div>
I am just encountering this issue (this is my first time with thymeleaf/spring). This is what solved it for me:
<div class="col-md-12" th:include="__${template}__ :: body" ...
In Thymeleaf 3.0, the following solution has worked for me:
<div th:replace="('fragments/' + ${template}) :: (${template})">
(Note however, that I use it with fixed name of the fragment and dynamic name of the template, so the parantheses around :: (${template}) might be optional.)
The solution is inspired by documentation for Thymeleaf in https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#fragment-specification-syntax
Both templatename and selector in the above examples can be fully-featured expressions (even conditionals!) like:
<div th:insert="footer :: (${user.isAdmin}? #{footer.admin} : #{footer.normaluser})"></div>
Note again how the surrounding ~{...} envelope is optional in th:insert/th:replace
<div th:insert=“${subpage}::fragementName”>
Just change subpage names and you will dynamic behaviour in thymleaf

Resources