Giter VIP home page Giter VIP logo

gin-template's Introduction

gin-template

GoDoc

Golang template for gin framework!

Deprecated!!!

Please consider trying to migrate to Goview

Goview

Goview is a lightweight, simple and easy template library based on golang html/template for building Go web application. Please consider trying to migrate to Goview.

Feature

  • Easy and simple to use for gin framework.
  • Use golang html/template syntax.
  • Support configure master layout file.
  • Support configure template file extension.
  • Support configure templates directory.
  • Support configure cache template.
  • Support include file.
  • Support dynamic reload template(disable cache mode).
  • Support multiple templates for fontend and backend.
  • Support go.rice add all resource files to a executable.

Docs

See https://www.godoc.org/github.com/foolin/gin-template

Install

go get github.com/foolin/gin-template

Usage

package main

import (
	"github.com/gin-gonic/gin"
	"github.com/foolin/gin-template"
	"net/http"
)

func main() {
	router := gin.Default()

	//new template engine
	router.HTMLRender = gintemplate.Default()

	router.GET("/page", func(ctx *gin.Context) {
		ctx.HTML(http.StatusOK, "page.html", gin.H{"title": "Page file title!!"})
	})

	router.Run(":9090")
}

Configure

    TemplateConfig{
		Root:      "views", //template root path
		Extension: ".tpl", //file extension
		Master:    "layouts/master", //master layout file
		Partials:  []string{"partials/head"}, //partial files
		Funcs: template.FuncMap{
			"sub": func(a, b int) int {
				return a - b
			},
			// more funcs
		},
		DisableCache: false, //if disable cache, auto reload template file for debug.
	}

Render

Render with master

The ctx is instance of *gin.Context

//use name without extension `.html`
ctx.HTML(http.StatusOK, "index", gin.H{})

Render only file(not use master layout)

//use full name with extension `.html`
ctx.HTML(http.StatusOK, "page.html", gin.H{})

Include syntax

//template file
{{include "layouts/footer"}}

Examples

Basic example

package main

import (
	"github.com/gin-gonic/gin"
	"github.com/foolin/gin-template"
	"net/http"
)

func main() {
	router := gin.Default()

	//new template engine
	router.HTMLRender = gintemplate.Default()

	router.GET("/", func(ctx *gin.Context) {
		//render with master
		ctx.HTML(http.StatusOK, "index", gin.H{
			"title": "Index title!",
			"add": func(a int, b int) int {
				return a + b
			},
		})
	})


	router.GET("/page", func(ctx *gin.Context) {
		//render only file, must full name with extension
		ctx.HTML(http.StatusOK, "page.html", gin.H{"title": "Page file title!!"})
	})

	router.Run(":9090")
}

Project structure:

|-- app/views/
    |--- index.html          
    |--- page.html
    |-- layouts/
        |--- footer.html
        |--- master.html
    

See in "examples/basic" folder

Basic example

Advance example

package main

import (
	"github.com/gin-gonic/gin"
	"github.com/foolin/gin-template"
	"net/http"
	"html/template"
	"time"
)

func main() {
	router := gin.Default()

	//new template engine
	router.HTMLRender = gintemplate.New(gintemplate.TemplateConfig{
		Root:      "views",
		Extension: ".tpl",
		Master:    "layouts/master",
		Partials:  []string{"partials/ad"},
		Funcs: template.FuncMap{
			"sub": func(a, b int) int {
				return a - b
			},
			"copy": func() string{
				return time.Now().Format("2006")
			},
		},
		DisableCache: true,
	})

	router.GET("/", func(ctx *gin.Context) {
		//render with master
		ctx.HTML(http.StatusOK, "index", gin.H{
			"title": "Index title!",
			"add": func(a int, b int) int {
				return a + b
			},
		})
	})

	router.GET("/page", func(ctx *gin.Context) {
		//render only file, must full name with extension
		ctx.HTML(http.StatusOK, "page.tpl", gin.H{"title": "Page file title!!"})
	})

	router.Run(":9090")
}

Project structure:

|-- app/views/
    |--- index.tpl          
    |--- page.tpl
    |-- layouts/
        |--- footer.tpl
        |--- head.tpl
        |--- master.tpl
    |-- partials/
        |--- ad.tpl
    

See in "examples/advance" folder

Advance example

Multiple example

package main

import (
	"html/template"
	"net/http"
	"time"

	"github.com/foolin/gin-template"
	"github.com/gin-gonic/gin"
)

func main() {
	router := gin.Default()

	//new template engine
	router.HTMLRender = gintemplate.New(gintemplate.TemplateConfig{
		Root:      "views/fontend",
		Extension: ".html",
		Master:    "layouts/master",
		Partials:  []string{"partials/ad"},
		Funcs: template.FuncMap{
			"copy": func() string {
				return time.Now().Format("2006")
			},
		},
		DisableCache: true,
	})

	router.GET("/", func(ctx *gin.Context) {
		// `HTML()` is a helper func to deal with multiple TemplateEngine's.
		// It detects the suitable TemplateEngine for each path automatically.
		gintemplate.HTML(ctx, http.StatusOK, "index", gin.H{
			"title": "Fontend title!",
		})
	})

	//=========== Backend ===========//

	//new middleware
	mw := gintemplate.NewMiddleware(gintemplate.TemplateConfig{
		Root:      "views/backend",
		Extension: ".html",
		Master:    "layouts/master",
		Partials:  []string{},
		Funcs: template.FuncMap{
			"copy": func() string {
				return time.Now().Format("2006")
			},
		},
		DisableCache: true,
	})

	// You should use helper func `Middleware()` to set the supplied
	// TemplateEngine and make `HTML()` work validly.
	backendGroup := router.Group("/admin", mw)

	backendGroup.GET("/", func(ctx *gin.Context) {
		// With the middleware, `HTML()` can detect the valid TemplateEngine.
		gintemplate.HTML(ctx, http.StatusOK, "index", gin.H{
			"title": "Backend title!",
		})
	})

	router.Run(":9090")
}

Project structure:

|-- app/views/
    |-- fontend/
        |--- index.html
        |-- layouts/
            |--- footer.html
            |--- head.html
            |--- master.html
        |-- partials/
     	   |--- ad.html
    |-- backend/
        |--- index.html
        |-- layouts/
            |--- footer.html
            |--- head.html
            |--- master.html
        
See in "examples/multiple" folder

Multiple example

Block example

/*
 * Copyright 2018 Foolin.  All rights reserved.
 *
 * Use of this source code is governed by a MIT style
 * license that can be found in the LICENSE file.
 *
 */

package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
	"github.com/foolin/gin-template"
)

func main() {

	router := gin.Default()

	//new template engine
	router.HTMLRender = gintemplate.Default()

	router.GET("/", func(ctx *gin.Context) {
		ctx.HTML(http.StatusOK, "index", gin.H{
			"title": "Index title!",
			"add": func(a int, b int) int {
				return a + b
			},
		})
	})


	router.GET("/block", func(ctx *gin.Context) {
		ctx.HTML(http.StatusOK, "block", gin.H{"title": "Block file title!!"})
	})

	router.Run(":9090")
}

Project structure:

|-- app/views/
    |--- index.html          
    |--- block.html
    |-- layouts/
        |--- master.html
        
See in "examples/block" folder

Block example

go.rice example

/*
 * Copyright 2018 Foolin.  All rights reserved.
 *
 * Use of this source code is governed by a MIT style
 * license that can be found in the LICENSE file.
 *
 */

package main

import (
	"net/http"
	"github.com/GeertJohan/go.rice"
	"github.com/foolin/gin-template/supports/gorice"
	"github.com/gin-gonic/gin"
)

func main() {

	router := gin.Default()

	// servers other static files
	staticBox := rice.MustFindBox("static")
	router.StaticFS("/static", staticBox.HTTPBox())

	//new template engine
	router.HTMLRender = gorice.New(rice.MustFindBox("views"))

	// Routes
	router.GET("/", func(c *gin.Context) {
		//render with master
		c.HTML(http.StatusOK, "index", gin.H{
			"title": "Index title!",
			"add": func(a int, b int) int {
				return a + b
			},
		})
	})

	router.GET("/page", func(c *gin.Context) {
		//render only file, must full name with extension
		c.HTML(http.StatusOK, "page.html", gin.H{"title": "Page file title!!"})
	})

	// Start server
	router.Run(":9090")
}

Project structure:

|-- app/views/
    |--- index.html          
    |--- page.html
    |-- layouts/
        |--- footer.html
        |--- master.html
|-- app/static/  
    |-- css/
        |--- bootstrap.css   	
    |-- img/
        |--- gopher.png

See in "examples/gorice" folder

gorice example

Supports

Relative Template

gin-template's People

Contributors

0xhexe avatar appleboy avatar foolin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

gin-template's Issues

Multiple template problem

Hi

i have a login page and dont want use master page but other pages can be use master page.

i set .HTMLRender = gintemplate.New(gintemplate.TemplateConfig{
Root: "views",
Extension: ".html",
Master: "layouts/master",
Partials: []string{},
Funcs: template.FuncMap{
"copy": func() string {
return time.Now().Format("2018")
},
},
DisableCache: isDebugMode,
})

but my application start with login page set empty temlate config but give an error. it wants to use master page can you help me ?

emptyMasterPage := gintemplate.NewMiddleware(gintemplate.TemplateConfig{
	Root:         "views",
	Extension:    ".html",
	Master:       "",
	Partials:     []string{},
	DisableCache: true,
})

server.Engine().GET("/", func(ctx *gin.Context) {
	// With the middleware, `HTML()` can detect the valid TemplateEngine.
	gintemplate.HTML(ctx, http.StatusOK, "account/login", gin.H{
		"title": "Backend title!",
	})
},  server.EmptyMasterPage())

Proposal: unite the way to call HTML()

Excellent work!

And I think the call method for HTML is a bit complex in the multiple example. There are two ways to call HTML.

	router.GET("/", func(ctx *gin.Context) {
		//render with master
		ctx.HTML(http.StatusOK, "index", gin.H{
			"title": "Fontend title!",
		})
	})

	backendGroup.GET("/", func(ctx *gin.Context) {
		//render backend
		backendRender.HTML(ctx, http.StatusOK, "index", gin.H{
			"title": "Backend title!",
		})
	})

If possible, some helper functions can solve this, for instance...

package gintemplate

const engineKey = "github.com/foolin/gin-template/templateEngine"

func Middleware(e *TemplateEngine) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		ctx.Set(engineKey, e)
	}
}

func HTML(ctx *gin.Context, code int, name string, data interface{}) {
	// If found the engine in context, use that.
	if val, ok := ctx.Get(engineKey); ok {
		if r, ok := val.(*TemplateEngine); ok {
			r.HTML(ctx, code, name, data)
			return
		}
	}
	// If not, fallback to the default one.
	ctx.HTML(code, name, data)
}


package someApp

router.GET("/", func(ctx *gin.Context) {
	// the same way to use HTML
	gintempalte.HTML(ctx, http.StatusOK, "index", gin.H{})
})

backendGroup := router.Group("/admin", gintemplate.Middleware(backendRender))

backendGroup.GET("/", func(ctx *gin.Context) {
	// the same way to use HTML
	gintemplate.HTML(ctx, http.StatusOK, "index", gin.H{})
})

How about this? If you like, I can PR.

Link method delete

Is there any way to build link or form with method delete ? Maybe it is possible somehow customize link with JS to send request with redirect on user's page.

template error: html/template: "index" is an incomplete template

since go 1.10 a html page template fails with this error

a quick fix could be

diff --git a/template.go b/template.go
index 9295da9..5b93902 100644
--- a/template.go
+++ b/template.go
@@ -171,6 +171,7 @@ func (e *TemplateEngine) executeTemplate(out io.Writer, name string, data interf
                        if err != nil {
                                return fmt.Errorf("TemplateEngine render parser name:%v, path:%v, error: %v", v, path, err)
                        }
+                       tpl = t
                }
                e.tplMutex.Lock()
                e.tplMap[name] = tpl

but I don't make more tests for other cases

Gorice example not working in development mode

in example gorice:

remove generated rice-box.go (considered as development mode)
go build
./gorice

get panic when acess the http index:

could not locate box "views"

happends where to call gorice.New:

gorice.New(rice.MustFindBox("views"))

alt it works when as static assets: r.StaticFS("/assets", rice.MustFindBox("views").HTTPBox())

examples do not work

I try in exaples/multiple

go run main.go
and get panic:

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.

  • using env: export GIN_MODE=release
  • using code: gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET / --> main.main.func2 (3 handlers)
[GIN-debug] GET /admin/ --> main.main.func4 (4 handlers)
[GIN-debug] Listening and serving HTTP on :9090

�[31m2018/04/19 19:39:32 [Recovery] panic recovered:
GET / HTTP/1.1
Host: 127.0.0.1:9090
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Cache-Control: max-age=0
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0

runtime error: invalid memory address or nil pointer dereference
C:/Go/src/runtime/panic.go:491 (0x42c290)
gopanic: reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
C:/Go/src/runtime/panic.go:63 (0x42b114)
panicmem: panic(memoryError)
C:/Go/src/runtime/signal_windows.go:161 (0x4405a2)
sigpanic: panicmem()
D:/src/golang/src/github.com/foolin/gin-template/template.go:175 (0x777860)
(*TemplateEngine).executeTemplate: data, err = e.fileHandler(e.config, v)
D:/src/golang/src/github.com/foolin/gin-template/template.go:131 (0x776e75)
(*TemplateEngine).executeRender: return e.executeTemplate(out, name, data, useMaster)
D:/src/golang/src/github.com/foolin/gin-template/template.go:212 (0x77856b)
TemplateRender.Render: return r.Engine.executeRender(w, r.Name, r.Data)
:1 (0x778dc6)
D:/src/golang/src/github.com/gin-gonic/gin/context.go:427 (0x767048)
(*Context).Render: if err := r.Render(c.Writer); err != nil {
D:/src/golang/src/github.com/gin-gonic/gin/context.go:437 (0x767126)
(*Context).HTML: c.Render(code, instance)
D:/src/golang/src/github.com/foolin/gin-template/template.go:97 (0x77693f)
HTML: ctx.HTML(code, name, data)
D:/src/golang/src/gin-template/examples/multiple/main.go:40 (0x7797a0)
main.func2: gintemplate.HTML(ctx, http.StatusOK, "index", gin.H{
D:/src/golang/src/github.com/gin-gonic/gin/context.go:97 (0x765759)
(*Context).Next: c.handlersc.index
D:/src/golang/src/github.com/gin-gonic/gin/recovery.go:45 (0x774760)
RecoveryWithWriter.func1: c.Next()
D:/src/golang/src/github.com/gin-gonic/gin/context.go:97 (0x765759)
(*Context).Next: c.handlersc.index
D:/src/golang/src/github.com/gin-gonic/gin/logger.go:72 (0x773b67)
LoggerWithWriter.func1: c.Next()
D:/src/golang/src/github.com/gin-gonic/gin/context.go:97 (0x765759)
(*Context).Next: c.handlersc.index
D:/src/golang/src/github.com/gin-gonic/gin/gin.go:284 (0x76b7fa)
(*Engine).handleHTTPRequest: context.Next()
D:/src/golang/src/github.com/gin-gonic/gin/gin.go:265 (0x76b181)
(*Engine).ServeHTTP: engine.handleHTTPRequest(c)
C:/Go/src/net/http/server.go:2619 (0x6b70ea)
serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
C:/Go/src/net/http/server.go:1801 (0x6b3183)
(*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
C:/Go/src/runtime/asm_amd64.s:2337 (0x458090)
goexit: BYTE $0x90 // NOP
�[0m
exit status 2

In all examples i get the same. What is my mistake? I use latest gin-template from github? go 1.9.4 windosw/amd64.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.