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

Documentation issue in Components page #1024

Open
Hygens opened this issue Feb 11, 2025 · 7 comments
Open

Documentation issue in Components page #1024

Hygens opened this issue Feb 11, 2025 · 7 comments

Comments

@Hygens
Copy link

Hygens commented Feb 11, 2025

I attempt use that process to update value in text component but not work:
https://go-app.dev/components#updates

#Source code sample:

package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/maxence-charriere/go-app/v10/pkg/app"
)

// hello is a component that displays a simple "Hello World!". A component is a
// customizable, independent, and reusable UI element. It is created by
// embedding app.Compo into a struct.
type hello struct {
	app.Compo
	Msg string
}

// The Render method is where the component appearance is defined. Here, a
// "Hello World!" is displayed as a heading.
func (h *hello) Render() app.UI {
	h.Msg = "Just because Go and this package are really awesome!"
	return app.Div().Style("border", "2px solid black").
		Body(
			app.H1().
				Class("title").
				Text("Build a GUI with Go"),
			app.P().
				Class("text").
				Text(h.Msg),
		).
		OnClick(h.onClick)
}

func (h *hello) onClick(ctx app.Context, e app.Event) {
	h.Msg = "Sounds good!"
	h.Update()
}

func (h *hello) OnPreRender(ctx app.Context) {
	fmt.Println("component prerendered")
}

func (h *hello) OnMount(ctx app.Context) {
	fmt.Println("component mounted")
}

func (h *hello) OnNav(ctx app.Context) {
	fmt.Println("component navigated:")
}

func (h *hello) OnDismount() {
	fmt.Println("component dismounted")
}

// The main function is the entry point where the app is configured and started.
// It is executed in 2 different environments: A client (the web browser) and a
// server.
func main() {
	// The first thing to do is to associate the hello component with a path.
	//
	// This is done by calling the Route() function,  which tells go-app what
	// component to display for a given path, on both client and server-side.
	app.Route("/", func() app.Composer { return &hello{} })

	// Once the routes set up, the next thing to do is to either launch the app
	// or the server that serves the app.
	//
	// When executed on the client-side, the RunWhenOnBrowser() function
	// launches the app,  starting a loop that listens for app events and
	// executes client instructions. Since it is a blocking call, the code below
	// it will never be executed.
	//
	// When executed on the server-side, RunWhenOnBrowser() does nothing, which
	// lets room for server implementation without the need for precompiling
	// instructions.
	app.RunWhenOnBrowser()

	// Finally, launching the server that serves the app is done by using the Go
	// standard HTTP package.
	//
	// The Handler is an HTTP handler that serves the client and all its
	// required resources to make it work into a web browser. Here it is
	// configured to handle requests with a path that starts with "/".
	http.Handle("/", &app.Handler{
		Name:        "Hello",
		Description: "An Hello World! example",
	})

	if err := http.ListenAndServe(":8000", nil); err != nil {
		log.Fatal(err)
	}
}

#Compiling I get that:

go_app_sample]$ make run
GOARCH=wasm GOOS=js go build -o web/app.wasm -buildvcs=false
# go_app_sample
./main.go:37:4: h.Update undefined (type *hello has no field or method Update)
make: *** [Makefile:2: build] Error 1

I attempt that because no get any automatic update to app.Text component after change hello Msg field.

@oderwat
Copy link
Contributor

oderwat commented Feb 11, 2025

Make Msg lowercase.

@Hygens
Copy link
Author

Hygens commented Feb 11, 2025

Msg

Same problem. I think that this is bad interpretation because in Go exported field is uppercase and the documentation sample "Number" field is uppercase:

type myCompo struct {
	app.Compo

	Number int
}

func (c *myCompo) Render() app.UI {
	return app.Div().Text(c.Number)
}

func (c *myCompo) customTrigger() {
	c.Number = rand.Intn(42)
	c.Update() // Manual updated trigger
}

The code changed:

package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/maxence-charriere/go-app/v10/pkg/app"
)

// hello is a component that displays a simple "Hello World!". A component is a
// customizable, independent, and reusable UI element. It is created by
// embedding app.Compo into a struct.
type hello struct {
	app.Compo
	msg string
}

// The Render method is where the component appearance is defined. Here, a
// "Hello World!" is displayed as a heading.
func (h *hello) Render() app.UI {
	h.msg = "Just because Go and this package are really awesome!"
	return app.Div().Style("border", "2px solid black").
		Body(
			app.H1().
				Class("title").
				Text("Build a GUI with Go"),
			app.P().
				Class("text").
				Text(h.msg),
		).
		OnClick(h.onClick)
}

func (h *hello) onClick(ctx app.Context, e app.Event) {
	h.msg = "Sounds good!"
	h.Update()
}

func (h *hello) OnPreRender(ctx app.Context) {
	fmt.Println("component prerendered")
}

func (h *hello) OnMount(ctx app.Context) {
	fmt.Println("component mounted")
}

func (h *hello) OnNav(ctx app.Context) {
	fmt.Println("component navigated:")
}

func (h *hello) OnDismount() {
	fmt.Println("component dismounted")
}

// The main function is the entry point where the app is configured and started.
// It is executed in 2 different environments: A client (the web browser) and a
// server.
func main() {
	// The first thing to do is to associate the hello component with a path.
	//
	// This is done by calling the Route() function,  which tells go-app what
	// component to display for a given path, on both client and server-side.
	app.Route("/", func() app.Composer { return &hello{} })

	// Once the routes set up, the next thing to do is to either launch the app
	// or the server that serves the app.
	//
	// When executed on the client-side, the RunWhenOnBrowser() function
	// launches the app,  starting a loop that listens for app events and
	// executes client instructions. Since it is a blocking call, the code below
	// it will never be executed.
	//
	// When executed on the server-side, RunWhenOnBrowser() does nothing, which
	// lets room for server implementation without the need for precompiling
	// instructions.
	app.RunWhenOnBrowser()

	// Finally, launching the server that serves the app is done by using the Go
	// standard HTTP package.
	//
	// The Handler is an HTTP handler that serves the client and all its
	// required resources to make it work into a web browser. Here it is
	// configured to handle requests with a path that starts with "/".
	http.Handle("/", &app.Handler{
		Name:        "Hello",
		Description: "An Hello World! example",
	})

	if err := http.ListenAndServe(":8000", nil); err != nil {
		log.Fatal(err)
	}
}

The error:

make run
GOARCH=wasm GOOS=js go build -o web/app.wasm -buildvcs=false
# go_app_sample
./main.go:37:4: h.Update undefined (type *hello has no field or method Update)
make: *** [Makefile:2: build] Error 1

@oderwat
Copy link
Contributor

oderwat commented Feb 11, 2025

  • You need lowercase fields when you want to change the field from inside the component. Uppercase is used when you want to control the content from the outside (hence it is "exported").
  • You do not need to call h.Update() and this also does not exists in the current Go-App API. You find that as "context.Update()" and it is only needed to trigger an update of your component, when you are doing updates outside of event handlers. Something like using it in a Go-Routine for example.
  • Your Render() function resets the text to the initial value on each render. This parts need to go into "OnMount()" (or OnInit(), depending on it being initialized for each new mount of the component or only once when the component gets created).
  • You should also swap fmt.Println() with app.Log()

@Hygens
Copy link
Author

Hygens commented Feb 11, 2025

  • You need lowercase fields when you want to change the field from inside the component. Uppercase is used when you want to control the content from the outside (hence it is "exported").
  • You do not need to call h.Update() and this also does not exists in the current Go-App API. You find that as "context.Update()" and it is only needed to trigger an update of your component, when you are doing updates outside of event handlers. Something like using it in a Go-Routine for example.
  • Your Render() function resets the text to the initial value on each render. This parts need to go into "OnMount()" (or OnInit(), depending on it being initialized for each new mount of the component or only once when the component gets created).
  • You should also swap fmt.Println() with app.Log()

Ok work with onMount and changed the value clicking on DIV. Please if possible verify I opened the issue because the documentation online is outdated and for that I was using incorrect.

Thanks,

@maxence-charriere
Copy link
Owner

This can’t work.
You are setting h.Msg into the Render method. Whathever you do in onclick, it will go back to what you set in the render method.

@oderwat
Copy link
Contributor

oderwat commented Feb 11, 2025

I think that @maxence-charriere is working on a updated documentation.

Hehe. There he is :)

@Hygens
Copy link
Author

Hygens commented Feb 11, 2025

This can’t work. You are setting h.Msg into the Render method. Whathever you do in onclick, it will go back to what you set in the render method.

@maxence-charriere , That is solved. Thank you.

package main

import (
	"log"
	"net/http"

	"github.com/maxence-charriere/go-app/v10/pkg/app"
)

// hello is a component that displays a simple "Hello World!". A component is a
// customizable, independent, and reusable UI element. It is created by
// embedding app.Compo into a struct.
type hello struct {
	app.Compo
	msg string
}

// The Render method is where the component appearance is defined. Here, a
// "Hello World!" is displayed as a heading.
func (h *hello) Render() app.UI {
	return app.Div().Style("border", "2px solid black").
		Body(
			app.H1().
				Class("title").
				Text("Build a GUI with Go"),
			app.P().
				Class("text").
				Text(h.msg),
		).
		OnClick(h.onClick)
}

func (h *hello) onClick(ctx app.Context, e app.Event) {
	h.msg = "Sounds good!"
	app.Log("onClick", h.msg)
}

func (h *hello) OnPreRender(ctx app.Context) {
	app.Log("component prerendered")
}

func (h *hello) OnMount(ctx app.Context) {
	h.msg = "Just because Go and this package are really awesome!"
	app.Log("component mounted")
}

func (h *hello) OnNav(ctx app.Context) {
	app.Log("component navigated:")
}

func (h *hello) OnDismount() {
	app.Log("component dismounted")
}

// The main function is the entry point where the app is configured and started.
// It is executed in 2 different environments: A client (the web browser) and a
// server.
func main() {
	// The first thing to do is to associate the hello component with a path.
	//
	// This is done by calling the Route() function,  which tells go-app what
	// component to display for a given path, on both client and server-side.
	app.Route("/", func() app.Composer { return &hello{} })

	// Once the routes set up, the next thing to do is to either launch the app
	// or the server that serves the app.
	//
	// When executed on the client-side, the RunWhenOnBrowser() function
	// launches the app,  starting a loop that listens for app events and
	// executes client instructions. Since it is a blocking call, the code below
	// it will never be executed.
	//
	// When executed on the server-side, RunWhenOnBrowser() does nothing, which
	// lets room for server implementation without the need for precompiling
	// instructions.
	app.RunWhenOnBrowser()

	// Finally, launching the server that serves the app is done by using the Go
	// standard HTTP package.
	//
	// The Handler is an HTTP handler that serves the client and all its
	// required resources to make it work into a web browser. Here it is
	// configured to handle requests with a path that starts with "/".
	http.Handle("/", &app.Handler{
		Name:        "Hello",
		Description: "An Hello World! example",
	})

	if err := http.ListenAndServe(":8000", nil); err != nil {
		log.Fatal(err)
	}
}

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

No branches or pull requests

3 participants