Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how I can render template multiple times in a handler without return? #2440

Open
mor7eza opened this issue Apr 28, 2023 · 6 comments
Open

how I can render template multiple times in a handler without return? #2440

mor7eza opened this issue Apr 28, 2023 · 6 comments

Comments

@mor7eza
Copy link

mor7eza commented Apr 28, 2023

Question Description

Hi everyone,
I have a handler that process large data and I want show and update a progress bar in my html page. How I can render a template multiple times without return from handler?
for example calling c.Render("page", fiber.Map{}) multiple time to update a progressbar.

thanks

@welcome
Copy link

welcome bot commented Apr 28, 2023

Thanks for opening your first issue here! 🎉 Be sure to follow the issue template! If you need help or want to chat with us, join us on Discord https://gofiber.io/discord

@ghost
Copy link

ghost commented Apr 28, 2023

It's not possible via just using c.Render(...) you should use SSE for that
Take a look at the official recipes repo for an example of SSE

@ReneWerner87
Copy link
Member

The current functionality in fiber core itself is only designed to render once per route and runs for the majority of cases

However, if you need multiple rendering or multiple different engines, you can use them as the core does

The respective engines get a buffer for storage of the output data in the egine render method

https://github.com/gofiber/fiber/blob/master/ctx.go#L1433

@gooddavvy
Copy link

Question Description

Hi everyone, I have a handler that process large data and I want show and update a progress bar in my html page. How I can render a template multiple times without return from handler? for example calling c.Render("page", fiber.Map{}) multiple time to update a progressbar.

thanks

Could you give me extra code to understand?

@ReneWerner87
Copy link
Member

ReneWerner87 commented Jun 28, 2023

@gooddavvy

package main

import (
	"fmt"
	"log"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/template/handlebars/v2"
	"github.com/gofiber/template/html/v2"
	"github.com/gofiber/template/jet/v2"
	"github.com/valyala/bytebufferpool"
)

func main() {

	htmlEngine := html.New("./html", ".html")
	handlebarsEngine := handlebars.New("./handlebars", ".hbs")
	jetEngine := jet.New("./jet", ".jet")

	if err := htmlEngine.Load(); err != nil {
		log.Fatalf("[Warning]: failed to load views: %v\n", err)
	}
	if err := handlebarsEngine.Load(); err != nil {
		log.Fatalf("[Warning]: failed to load views: %v\n", err)
	}
	if err := jetEngine.Load(); err != nil {
		log.Fatalf("[Warning]: failed to load views: %v\n", err)
	}

	app := fiber.New(fiber.Config{
		Views: htmlEngine,
	})

	app.Get("/html", func(ctx *fiber.Ctx) error {
		return ctx.Render("index", fiber.Map{"Title": "htmlTemplate"})
	})
	app.Get("/handlebars", func(ctx *fiber.Ctx) error {
		buf := bytebufferpool.Get()
		defer bytebufferpool.Put(buf)
		if err := handlebarsEngine.Render(buf, "index", fiber.Map{"Title": "handlebarsTemplate"} /** ,Layout parameter **/); err != nil {
			return fmt.Errorf("failed to render: %w", err)
		}

		// Set rendered template to body
		return ctx.Type("html").Send(buf.Bytes())
	})
	app.Get("/jet", func(ctx *fiber.Ctx) error {
		buf := bytebufferpool.Get()
		defer bytebufferpool.Put(buf)
		if err := jetEngine.Render(buf, "index", fiber.Map{"Title": "jetTemplate"} /** ,Layout parameter **/); err != nil {
			return fmt.Errorf("failed to render: %w", err)
		}

		// Set rendered template to body
		return ctx.Type("html").Send(buf.Bytes())
	})

	log.Fatalln(app.Listen(":3000"))
}

image

handlebars/index.hbs

<!DOCTYPE html>
<html lang="en">
<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">
</head>
<body>
<h1>{{Title}}</h1>
</body>
</html>

html/index.html

<!DOCTYPE html>
<html lang="en">
<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">
</head>
<body>
<h1>{{.Title}}</h1>
</body>
</html>

jet/index.jet

<!DOCTYPE html>
<html lang="en">
<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">
</head>
<body>
<h1>{{Title}}</h1>
</body>
</html>

@ReneWerner87
Copy link
Member

oh i misread, you didn't want to render with different template engines, you wanted something more dynamic, what you normally get with streaming or websocket connections or polling

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants