problem with page render
gmax79 opened this issue · comments
Why does render not work correctly in this example?
Only one element is updated, although the entire page is recreated.
The error occurs if a line is added to the middle of the list (sorting)
type item struct {
app.Compo
name string
}
func (t *item) Render() app.UI {
return app.Div().Body(
app.Text(t.name),
)
}
type form struct {
app.Compo
value string
}
func (f *form) Render() app.UI {
return app.Div().Body(
app.Input().Type("text").Value(f.value).OnChange(f.ValueTo(&f.value)),
app.Button().Text("ADD").OnClick(
func(ctx app.Context, e app.Event) {
ctx.NewAction("update")
},
),
)
}
type Test struct {
app.Compo
page app.UI
Items []string
form *form
}
func (p *Test) OnMount(ctx app.Context) {
ctx.Handle("update", func(app.Context, app.Action) {
p.Items = append(p.Items, p.form.value)
sort.Strings(p.Items)
p.OnNav(ctx)
p.Update()
})
p.Items = []string{"a", "b"}
p.form = &form{}
}
func (p *Test) OnNav(ctx app.Context) {
c := make([]app.UI, 0)
for _, n := range p.Items {
c = append(c, &item{name: n})
}
c = append(c, p.form)
p.page = app.Div().Body(c...)
}
func (p *Test) Render() app.UI {
if app.IsServer {
return app.Text("")
}
if p.page == nil {
return app.Text("")
}
return p.page
}
See this explanation: #672 (comment)
Changing the Name field to exported will cause the correct sort and update.
type item struct {
app.Compo
Name string
}
Calling OnNav
from your code a bit unusual, that's typically called only from the go-app
framework.
Here's your example code slightly re-written using action tags for passing the value
and removing OnNav
, p.page
, and p.form
.
type item struct {
app.Compo
Name string
}
func (t *item) Render() app.UI {
return app.Div().Body(
app.Text(t.Name),
)
}
type form struct {
app.Compo
value string
}
func (f *form) Render() app.UI {
return app.Div().Body(
app.Input().Type("text").Value(f.value).OnChange(f.ValueTo(&f.value)),
app.Button().Text("ADD").OnClick(
func(ctx app.Context, e app.Event) {
ctx.NewAction("update", app.T("value", f.value))
},
),
)
}
type Test struct {
app.Compo
Items []string
}
func (p *Test) OnMount(ctx app.Context) {
p.Items = []string{"a", "b"}
ctx.Handle("update", func(ctx app.Context, action app.Action) {
p.Items = append(p.Items, action.Tags.Get("value"))
})
}
func (p *Test) Render() app.UI {
sort.Strings(p.Items)
c := make([]app.UI, len(p.Items)+1)
for i, s := range p.Items {
c[i] = &item{Name: s}
}
c = append(c, &form{})
return app.Div().Body(c...)
}
@mlctrez Thanks for the help.
The reason why I do prerender in OnNav is because there is no context in Render function.
More complex pages often need context
We also do things in OnNav
when we use the URL as route for the page for example.