Giter VIP home page Giter VIP logo

goview's Introduction

goview

GoDoc Widget Travis Widget GoReportCard Widget

Goview is a lightweight, minimalist and idiomatic template library based on golang html/template for building Go web application.

Contents

Install

go get github.com/foolin/goview

Features

  • Lightweight - use golang html/template syntax.
  • Easy - easy use for your web application.
  • Fast - Support configure cache template.
  • Include syntax - Support include file.
  • Master layout - Support configure master layout file.
  • Extension - Support configure template file extension.
  • Easy - Support configure templates directory.
  • Auto reload - Support dynamic reload template(disable cache mode).
  • Multiple Engine - Support multiple templates for frontend and backend.
  • No external dependencies - plain ol' Go html/template.
  • Gorice - Support gorice for package resources.
  • Gin/Iris/Echo/Chi - Support gin framework, Iris framework, echo framework, go-chi framework.

Docs

See https://www.godoc.org/github.com/foolin/goview

Supports

Usage

Overview

Project structure:

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

Use default instance:

    //write http.ResponseWriter
    //"index" -> index.html
    goview.Render(writer, http.StatusOK, "index", goview.M{})

Use new instance with config:

    gv := goview.New(goview.Config{
        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,
	Delims:    Delims{Left: "{{", Right: "}}"},
    })
    
    //Set new instance
    goview.Use(gv)
    
    //write http.ResponseWriter
    goview.Render(writer, http.StatusOK, "index", goview.M{})

Use multiple instance with config:

    //============== Frontend ============== //
    gvFrontend := goview.New(goview.Config{
        Root:      "views/frontend",
        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,
	Delims:       Delims{Left: "{{", Right: "}}"},
    })
    
    //write http.ResponseWriter
    gvFrontend.Render(writer, http.StatusOK, "index", goview.M{})
    
    //============== Backend ============== //
    gvBackend := goview.New(goview.Config{
        Root:      "views/backend",
        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,
	Delims:       Delims{Left: "{{", Right: "}}"},
    })
    
    //write http.ResponseWriter
    gvBackend.Render(writer, http.StatusOK, "index", goview.M{})

Config

goview.Config{
    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.
    Delims:       Delims{Left: "{{", Right: "}}"},
}

Include syntax

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

Render name:

Render name use index without .html extension, that will render with master layout.

  • "index" - Render with master layout.
  • "index.html" - Not render with master layout.
Notice: `.html` is default template extension, you can change with config

Render with master

//use name without extension `.html`
goview.Render(w, http.StatusOK, "index", goview.M{})

The w is instance of http.ResponseWriter

Render only file(not use master layout)

//use full name with extension `.html`
goview.Render(w, http.StatusOK, "page.html", goview.M{})

Custom template functions

We have two type of functions global functions, and temporary functions.

Global functions are set within the config.

goview.Config{
	Funcs: template.FuncMap{
		"reverse": e.Reverse,
	},
}
//template file
{{ reverse "route-name" }}

Temporary functions are set inside the handler.

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
	err := goview.Render(w, http.StatusOK, "index", goview.M{
		"reverse": e.Reverse,
	})
	if err != nil {
		fmt.Fprintf(w, "Render index error: %v!", err)
	}
})
//template file
{{ call $.reverse "route-name" }}

Examples

See _examples/ for a variety of examples.

Basic example

package main

import (
	"fmt"
	"github.com/foolin/goview"
	"net/http"
)

func main() {

	//render index use `index` without `.html` extension, that will render with master layout.
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		err := goview.Render(w, http.StatusOK, "index", goview.M{
			"title": "Index title!",
			"add": func(a int, b int) int {
				return a + b
			},
		})
		if err != nil {
			fmt.Fprintf(w, "Render index error: %v!", err)
		}

	})

	//render page use `page.tpl` with '.html' will only file template without master layout.
	http.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) {
		err := goview.Render(w, http.StatusOK, "page.html", goview.M{"title": "Page file title!!"})
		if err != nil {
			fmt.Fprintf(w, "Render page.html error: %v!", err)
		}
	})

	fmt.Println("Listening and serving HTTP on :9090")
	http.ListenAndServe(":9090", nil)

}

Project structure:

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

See in "examples/basic" folder

Basic example

Gin example

go get github.com/foolin/goview/supports/ginview
package main

import (
	"github.com/foolin/goview/supports/ginview"
	"github.com/gin-gonic/gin"
	"net/http"
)

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

	//new template engine
	router.HTMLRender = ginview.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

Gin example

Iris example

$ go get github.com/foolin/goview/supports/irisview
package main

import (
	"github.com/foolin/goview/supports/irisview"
	"github.com/kataras/iris/v12"
)

func main() {
	app := iris.New()

	// Register the goview template engine.
	app.RegisterView(irisview.Default())

	app.Get("/", func(ctx iris.Context) {
		// Render with master.
		ctx.View("index", iris.Map{
			"title": "Index title!",
			"add": func(a int, b int) int {
				return a + b
			},
		})
	})

	app.Get("/page", func(ctx iris.Context) {
		// Render only file, must full name with extension.
		ctx.View("page.html", iris.Map{"title": "Page file title!!"})
	})

	app.Listen(":9090")
}

Project structure:

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

See in "examples/iris" folder

Iris example

Iris multiple example

package main

import (
	"html/template"
	"time"

	"github.com/foolin/goview"
	"github.com/foolin/goview/supports/irisview"
	"github.com/kataras/iris/v12"
)

func main() {
	app := iris.New()

	// Register a new template engine.
	app.RegisterView(irisview.New(goview.Config{
		Root:      "views/frontend",
		Extension: ".html",
		Master:    "layouts/master",
		Partials:  []string{"partials/ad"},
		Funcs: template.FuncMap{
			"copy": func() string {
				return time.Now().Format("2006")
			},
		},
		DisableCache: true,
	}))

	app.Get("/", func(ctx iris.Context) {
		ctx.View("index", iris.Map{
			"title": "Frontend title!",
		})
	})

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

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

	backendGroup := app.Party("/admin", mw)

	backendGroup.Get("/", func(ctx iris.Context) {
		// Use the ctx.View as you used to. Zero changes to your codebase,
		// even if you use multiple templates.
		ctx.View("index", iris.Map{
			"title": "Backend title!",
		})
	})

	app.Listen(":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/iris-multiple" folder

Iris multiple example

Echo example

Echo <=v3 version:

go get github.com/foolin/goview/supports/echoview

Echo v4 version:

go get github.com/foolin/goview/supports/echoview-v4
package main

import (
	"github.com/foolin/goview/supports/echoview"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
	"net/http"
)

func main() {

	// Echo instance
	e := echo.New()

	// Middleware
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())

	//Set Renderer
	e.Renderer = echoview.Default()

	// Routes
	e.GET("/", func(c echo.Context) error {
		//render with master
		return c.Render(http.StatusOK, "index", echo.Map{
			"title": "Index title!",
			"add": func(a int, b int) int {
				return a + b
			},
		})
	})

	e.GET("/page", func(c echo.Context) error {
		//render only file, must full name with extension
		return c.Render(http.StatusOK, "page.html", echo.Map{"title": "Page file title!!"})
	})

	// Start server
	e.Logger.Fatal(e.Start(":9090"))
}

Project structure:

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

See in "examples/basic" folder

Echo example Echo v4 example

Go-chi example

package main

import (
	"fmt"
	"github.com/foolin/goview"
	"github.com/go-chi/chi"
	"net/http"
)

func main() {

	r := chi.NewRouter()

	//render index use `index` without `.html` extension, that will render with master layout.
	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		err := goview.Render(w, http.StatusOK, "index", goview.M{
			"title": "Index title!",
			"add": func(a int, b int) int {
				return a + b
			},
		})
		if err != nil {
			fmt.Fprintf(w, "Render index error: %v!", err)
		}
	})

	//render page use `page.tpl` with '.html' will only file template without master layout.
	r.Get("/page", func(w http.ResponseWriter, r *http.Request) {
		err := goview.Render(w, http.StatusOK, "page.html", goview.M{"title": "Page file title!!"})
		if err != nil {
			fmt.Fprintf(w, "Render page.html error: %v!", err)
		}
	})

	fmt.Println("Listening and serving HTTP on :9090")
	http.ListenAndServe(":9090", r)

}

Project structure:

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

See in "examples/basic" folder

Chi example

Advance example

package main

import (
	"fmt"
	"github.com/foolin/goview"
	"html/template"
	"net/http"
	"time"
)

func main() {

	gv := goview.New(goview.Config{
		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,
	})

	//Set new instance
	goview.Use(gv)

	//render index use `index` without `.html` extension, that will render with master layout.
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		err := goview.Render(w, http.StatusOK, "index", goview.M{
			"title": "Index title!",
			"add": func(a int, b int) int {
				return a + b
			},
		})
		if err != nil {
			fmt.Fprintf(w, "Render index error: %v!", err)
		}

	})

	//render page use `page.tpl` with '.html' will only file template without master layout.
	http.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) {
		err := goview.Render(w, http.StatusOK, "page.tpl", goview.M{"title": "Page file title!!"})
		if err != nil {
			fmt.Fprintf(w, "Render page.html error: %v!", err)
		}
	})

	fmt.Println("Listening and serving HTTP on :9090")
	http.ListenAndServe(":9090", nil)
}

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/goview"
	"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

go.rice example

go get github.com/foolin/goview/supports/gorice
package main

import (
	"fmt"
	"github.com/GeertJohan/go.rice"
	"github.com/foolin/goview"
	"github.com/foolin/goview/supports/gorice"
	"net/http"
)

func main() {

	//static
	staticBox := rice.MustFindBox("static")
	staticFileServer := http.StripPrefix("/static/", http.FileServer(staticBox.HTTPBox()))
	http.Handle("/static/", staticFileServer)

	//new view engine
	gv := gorice.New(rice.MustFindBox("views"))
	//set engine for default instance
	goview.Use(gv)

	//render index use `index` without `.html` extension, that will render with master layout.
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		err := goview.Render(w, http.StatusOK, "index", goview.M{
			"title": "Index title!",
			"add": func(a int, b int) int {
				return a + b
			},
		})
		if err != nil {
			fmt.Fprintf(w, "Render index error: %v!", err)
		}

	})

	//render page use `page.tpl` with '.html' will only file template without master layout.
	http.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) {
		err := goview.Render(w, http.StatusOK, "page.html", goview.M{"title": "Page file title!!"})
		if err != nil {
			fmt.Fprintf(w, "Render page.html error: %v!", err)
		}
	})

	fmt.Println("Listening and serving HTTP on :9090")
	http.ListenAndServe(":9090", nil)
}

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

More examples

See _examples/ for a variety of examples.

Todo

[ ] Add Partials support directory or glob [ ] Add functions support.

goview's People

Contributors

danstewart avatar dependabot[bot] avatar foolin avatar fuadarradhi avatar kataras avatar wsantos 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  avatar  avatar

goview's Issues

go get error

OS: Windows 10 Pro 64 bit
go version: go1.15.4 windows/amd64

Apologies if this is a GitHub issue vs. something specific to this repository. I'm still learning how the go module system interacts with git.

I have a simple go Echo app running that uses the default Echo templating engine. The app imports a number of modules successfully, e.g.-

import (
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"

	"gitlab.com/colin_e_nhsd/eprom.git/backend"
)

this works fine.

However when I tried to add goview-v4 I was unable to access the repo. If I run-

go get github.com/foolin/goview-v4 as a first step in either a Powershell window (I'm on Windows) or the VSCode terminal I get two popup GitHub password prompts one after the other, then the download aborts after a lengthy timeout.

UPDATE
I think this error is a combination of a documentation issue on page- https://github.com/foolin/goview/tree/master/supports/echoview-v4 plus the fact that Github gives confusing errors about authentication failures when what it means is "repo or page not found".

On the supports/echoview-v4 doc page the first few lines say-

Install

go get -u github.com/foolin/goview-v4
go get -u github.com/foolin/goview/supports/echoview-v4

Example

package main

import (
	"github.com/foolin/goview/supports/echoview"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
	"net/http"
)

the line go get -u github.com/foolin/goview-v4 fails because there is no such module or package. The following line go get -u github.com/foolin/goview/supports/echoview-v4 succeeds, but I assume that means thre will be unresolved dependencies.

Meanwhile, the imports don't seem to be consistent either with the module dependencies above (no -v4 suffix) nor the correct imports for Echo v4 itself, which is imported as-

	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"

Any chance of updating the documentation here? I'm not entirely clear if this package is module-aware, which is significant now Echo v4 is set up as modules.

How about partial support with `_` prefix?

Hi, I'm working on a small Go project and would like to organize my HTML files properly. For example, if there's a dashboard screen with a form and a table, I'll put the form and table in separate partial files within the same folder, prefixed with _.

views/
├─ dashboard/
├── index.html
├── _table.html
├── _form.html

And here's the way configured it

config := goview.Config{
    ...
    Partials:  getPartialList(),
    ...
}

goview.New(config)

// .....

func getPartialList() []string {
	partials := []string{}

	err := filepath.Walk(ROOT_VIEW_PATH, func(path string, info fs.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if !info.IsDir() {
			fileName := info.Name()
			fileExtension := filepath.Ext(fileName)

			if fileExtension == ".html" && strings.HasPrefix(fileName, "_") {
				filePath := strings.Split(path, ROOT_VIEW_PATH)[1]
				filePathWithoutExt := filePath[:len(filePath)-len(fileExtension)]
				partials = append(partials, filePathWithoutExt)
			}
		}

		return nil
	})

	if err != nil {
		log.Info("Fail to get partial files", err.Error())
	}

	return partials
}

I saw one of the open issue also mention a need for a way to configure a partial folder and I think maybe registering any HTML file prefixed with _ within the view folder might be a good idea.
So I just want to propose this idea so you don't need to manually add your folder list or write a function to get all of your partial paths to be able to use them as partials.

How can i use go.rice in gin via goview, like git-template

gorice and gin is work fine in foolin/gin-template

router.HTMLRender = gorice.New(rice.MustFindBox("views"))

but now, I will use go.rice via goview, built app throw error no such file or directory

panic recovered:
ViewEngine render read name:base/master, path:/tmp/templates/views/base/master.tmpl, error: open /tmp/templates/views/base/master.tmpl: no such file or directory

I think go.rice is not working.

my code:

r := gin.Default()

staticBox := rice.MustFindBox("templates/static")
viewBox := rice.MustFindBox("templates/views")
r.StaticFS("/static", staticBox.HTTPBox())

gv := gorice.NewWithConfig(viewBox, goview.Config{
  Root:      "templates/views",
  Extension: ".tmpl",
  Master:    "base/master",
})
goview.Use(gv)

r.HTMLRender = ginview.New(goview.Config{
  Root:      "templates/views",
  Extension: ".tmpl",
  Master:    "base/master",
})

r.GET("/", func(c *gin.Context) {
	ginview.HTML(c, http.StatusOK, "index", gin.H{
		"title":                  "Gin",
		"ginBladeManagerVersion": "v1",
		"goVersion":              runtime.Version(),
	})
})

How do I make gorice work in gin via goview?

How to return html directly?

	html :=  goview.
	//I want to get the html to perform string replacement operations on it, and the regular matching data, whether there is an error
	if regexp.MustCompile(`\d{9,10}`).MatchString(html){
		//Filter data here
	}
	c.HTML(200, name, _ht)

no matching versions for query "latest"

hi foolin!
am using echov4
am run with cmd: go get -u github.com/foolin/goview/supports/echoview-v4
Error:
go: finding github.com/foolin/goview/supports/echoview-v4 latest
go: finding github.com/foolin/goview/supports latest
go get github.com/foolin/goview/supports/echoview-v4: no matching versions for query "latest"
can you help me? thanks!

Switching between rendering with the parent layout or not by adding .HTML to template name

First of all, thank you for the work you've done; you have a great project.

The only thing that concerns me in your project is the use of .html in the template name. It affects whether the parent layout will be applied or not. In my opinion, this is a terrible decision that goes against the Go language ideology, where simplicity and clarity of the code are paramount. In this case, there is no clear way for a new project contributor to understand how the template name determines whether it will be rendered with the parent layout or not without documentation. I believe that, without breaking backward compatibility, it's possible to keep the option of using .html and add another, more explicit way to specify whether a template will be rendered with a parent layout or not.
Than you.

Issue when using on Gin Framework

I'm trying to use goview on Gin Framework.

I did following from one of the example:

r.HTMLRender = ginview.New(goview.Config{
		Root:      "./fe/views",
		Extension: ".html",
		Master:    "layouts/master",
		Partials:  []string{},
		Funcs: template.FuncMap{
			"copy": func() string {
				return time.Now().Format(strconv.Itoa(time.Now().Year()))
			},
		},
		DisableCache: false,
	})

master.html:

<!-- /views/admin/master.html -->
<!doctype html>

<html>
<head>
    <title>{{.title}}</title>
    {{template "head" .}}
</head>

<body>
{{template "content" .}}
<hr>
{{include "layouts/footer"}}
</body>
</html>

But when trying to access the page, I stumbled with following error:

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36


ViewEngine execute template error: html/template:layouts/master:11:11: no such template "content"
/Users/sujit/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:842 (0x155efa2)
        (*Context).Render: panic(err)
/Users/sujit/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:851 (0x155f048)
        (*Context).HTML: c.Render(code, instance)
/Users/sujit/Sites/labs/gin-rest/be/app/app.go:43 (0x157c533)
        Serve.func2: ctx.HTML(http.StatusOK, "index", gin.H{
/Users/sujit/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:161 (0x155b42a)
        (*Context).Next: c.handlers[c.index](c)
/Users/sujit/go/pkg/mod/github.com/gin-gonic/[email protected]/recovery.go:83 (0x156eb2f)
        RecoveryWithWriter.func1: c.Next()
/Users/sujit/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:161 (0x155b42a)
        (*Context).Next: c.handlers[c.index](c)
/Users/sujit/Sites/labs/gin-rest/be/app/Http/Middleware/request_id.go:23 (0x1572938)
        RequestId.func1: c.Next()
/Users/sujit/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:161 (0x155b42a)
        (*Context).Next: c.handlers[c.index](c)
/Users/sujit/go/pkg/mod/github.com/gin-gonic/[email protected]/recovery.go:83 (0x156eb2f)
        RecoveryWithWriter.func1: c.Next()
/Users/sujit/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:161 (0x155b42a)
        (*Context).Next: c.handlers[c.index](c)
/Users/sujit/go/pkg/mod/github.com/gin-gonic/[email protected]/logger.go:241 (0x156dc60)
        LoggerWithConfig.func1: c.Next()
/Users/sujit/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:161 (0x155b42a)
        (*Context).Next: c.handlers[c.index](c)
/Users/sujit/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:409 (0x1565205)
        (*Engine).handleHTTPRequest: c.Next()
/Users/sujit/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:367 (0x156491c)
        (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/Users/sujit/go/go1.14.2/src/net/http/server.go:2807 (0x12d4072)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/Users/sujit/go/go1.14.2/src/net/http/server.go:1895 (0x12cf9eb)
        (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/Users/sujit/go/go1.14.2/src/runtime/asm_amd64.s:1373 (0x1064870)
        goexit: BYTE    $0x90   // NOP

Shouldn't it work even though template "content" . exists

How to use Multitemplate for gin?

I see in your example using different template like 'gvFrontend' and 'gvBackend', But in gin, we can only pass one ViewEngine. Is there any example for gin?

How i can print html comment like knockout-if

There are some js library need using comment like knockout, how i can achieve this using goview?

<ul>
    <li>This item always appears</li>
    <!-- ko if: someExpressionGoesHere -->
        <li>I want to make this item present/absent dynamically</li>
    <!-- /ko -->
</ul>

Support for `PartialsDir` or `PartialsGlob`

Golang's native html supports template.ParseGlob, which I find quite useful. And for example, another template engine, extemplate, supports ParseDir.

Currently, goview requires all partials to be listed in goview.Config. Would it be possible to add support to include partials recursively from specific base directory? Or, include partials matching specific glob?

Auto complete Extensions

The file extension should not be added if it's already provided in the include instruction:

Example:
I use the default configuration of goview, (so the Extensions is ".html")

error.html:

{{define "head"}}
    {{include "style.css"}}
{{end}}

{{define "content"}}
    <h1>Error</h1>
{{end}}

style.css:

body {
background-color: red;
}

The error I get:

ViewEngine execute template error: template: error:2:6: executing "head" at <include "style.css">: error calling include: ViewEngine render read name:style.css, path:<gopath>/github.com/<username>/<projectname>/service.web.oauth/views/style.css.html, error: open <gopath>/github.com/<username>/<projetctname>/service.web.oauth/views/style.css.html: no such file or directory

Compile templates into server executable

Not sure if this is possible, but I'm trying to compile the templates/static files into the binary so that when I run the executable elsewhere, I don't also have to figure out how to ship assets - that is to say, it's all included within the compiled go binary.

I've done this before with static assets utilizing go-bindata, but not sure if there is a way to do it for goview.

In my case, I'm specifically utilizing goview with gin (via ginview) but hopefully that doesn't impact the answer.

Great work btw, this package looks awesome!

extends syntax

How hard would it be to add a extends function so we can have "multiple" masters, I need to have some pages without footer and header and right now it's set on the master layout, without it, I'll need to set footer and master on most of my pages just to have 1/2 pages without footer and master, thanks in advance.

why not support a method to dynamic clear cache ?

I set the view engine DisableCache false , but I also need dynamic the clear the cache.

can you support a method like this ?

func (e *ViewEngine) ClearAllCache() {
e.tplMutex.RLock()
e.tplMap = make(map[string]*template.Template)
e.tplMutex.RUnlock()
}
I also suggest change DisableCache to Cache ?

Had to abandon this tool

This engine does not currently work(at least echo view) and had to be abandoned for a project I was working on. You are not able to pass data from the handlers to the templates, instead it crashes the Echo app.

I'm not sure if this is true of the other versions, but Echoview is unusable.

Question about how to call a function

What is the diference about calling a function with/without {{ call $.funname params }} ?

I've been trying to add the reverse URL function to the function and it only works without call $. but I'm not sure what it's right or wrong since this is not documented

My render

	//Set Renderer
	e.Renderer = echoview.New(goview.Config{
		Root:      "app/templates",
		Extension: ".html",
		Master:    "layouts/master",
		Partials:  []string{},
		Funcs: template.FuncMap{
			"reverse": e.Reverse,
		},
		DisableCache: false,
	})

This works

{{ reverse "board_create" }}

This throws an error

{{ call $.reverse "board_create" }}

Error: "ViewEngine execute template error: template: layouts/master:15:6: executing "layouts/master" at \u003cinclude "layouts/header"\u003e: error calling include: ViewEngine execute template error: template: layouts/header:15:23: executing "layouts/header" at \u003ccall $.reverse "board_create"\u003e: error calling call: call of nil"

Context pre-processors

Hi I need to extract data from context and expose it to the template, mainly sure info so I can show that the user is logged in on the page header, do we have a way to do it ? do you think that maybe we can have the same functionality as Config.Funcs but they receive context? here it's my test middleware and the data I need available on all templates.

// UserAuth -
func (m *Middleware) UserAuth(next echo.HandlerFunc) echo.HandlerFunc {
	return func(c echo.Context) error {
		sess, _ := session.Get("session", c)
		userId, _ := sess.Values["user_id"].(int)

		user, _ := models.FindUser(c.Request().Context(), m.DB, userId)

		c.Set("user", user)

		return next(c)
	}
}

And for echoview I think that this needs to go here, echoview.go

// Render render template for echo interface
func (e *ViewEngine) Render(w io.Writer, name string, data interface{}, c echo.Context) error {

    // call all context processors and transform data

	return e.RenderWriter(w, name, data)
}

Let me know if that is a good approach, but I'm not sure how to fit this on other frameworks.

What file structure should I create to minimize duplication of html code?

Hi. I have such a file structure, index.html the main one, css styles and scripts are connected in it
image

the data that differ I have taken out in partials, I would like to index.html output {{template "ext" .}} or {{template "conf" .}} depending on the current page or get the parameter, is it possible to do this? Create a copy index.html , but with {{template "conf" .}} I would not like to because there can be a large number of pages

Additional funcs for templates

Hello.

Please help with advice. I don’t understand how I can add a new function after initializing the config.
For example, if we take the example "/multiple/main.go"
we have two configs like gvFront and gvBackend initialized before route.
How I can add a new function T into handler like:

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		err := gvFront.Render(w, http.StatusOK, "index", goview.M{
			"title": "Frontend title!",
                        "T": func(id string) string { return "AAAAAAAAAA!" },
		})
		if err != nil {
			fmt.Fprintf(w, "Render index error: %v!", err)
		}
	})

If we run this code, we will see an error:

Render index error: ViewEngine render parser name:index,
error: template: index:2: function "T" not defined!

Adding a function in the process is a prerequisite,
I do not need this function at the initialization stage of the config.

我想要从子页面向 master 中定义的 menu 传值应该如何处理?

目录结构:

C:.
│  index.html
│  manage-posts.html
│  write-post.html
│  
└─layouts
        foot.html
        head.html
        master.html
        menu.html

master长这样:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{.title}}</title>
    {{include "layouts/head"}}
</head>
<body>
    {{template "content" .}}
</body>
</html>

menu长这样:

<ul class="root focus">
    <li class="parent"><a href="/admin/index.php">控制台</a></li>
    <ul class="child">
        <li class="focus"><a href="/admin/">概要</a></li>
        <li><a href="/admin/profile.php">个人设置</a></li>
        <li><a href="/admin/plugins.php">插件</a></li>
        <li><a href="/admin/themes.php">外观</a></li>
        <li class="last"><a href="/admin/backup.php">备份</a></li>
    </ul>
</ul>

我想要根据当前路由动态的给menu的li加上 class="focus",请问有什么推荐的方式吗?

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.