Initial Sync
Recover form field values a browser refuses to clear on page reload.
Initial Sync
Some browsers, such as Firefox, will not clear data from form fields when the page is reloaded. To the user there is data in the field, and if they submit a form they expect that data to be recognised.
Initial sync is a client side process that will send this data to the server after a page refresh. You can check for this behavior in your event handlers.
This example also shows how to get multiple values from inputs that support that.
Live Demo
This example relies on the browser preserving form field values across a real page reload, which doesn't happen the same way inside an iframe.
Open live demo in a new tab ↗Source
package examples
import (
"context"
"strings"
l "github.com/SamHennessy/hlive"
. "github.com/SamHennessy/hlive/hhtml"
)
const initialSyncStyle l.HTML = `
.box {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 0.5em;
}
input, select {
width: 100%;
}
`
// InitialSyncDemo is a live, interactive instance of the Initial Sync
// example, served for the "Live Demo" iframe.
func InitialSyncDemo() *l.Page {
page := l.NewPage()
page.DOM().Title().Add("Form Data Initial Sync Example")
page.DOM().Head().Add(Link(Rel("stylesheet"), Href("https://cdn.simplecss.org/simple.min.css")))
page.DOM().Head().Add(Style(initialSyncStyle))
var (
formValsSync [9]*l.NodeBox[string]
formValsNoSync [len(formValsSync)]*l.NodeBox[string]
)
for i := 0; i < len(formValsSync); i++ {
formValsSync[i] = l.Box("")
formValsNoSync[i] = l.Box("")
}
page.DOM().Body().Add(
Header(
H1("Form Data Initial Sync"),
P("Some browsers, life FireFox, don't clear form field data after a page reload. "+
"HLive will send this data to relevant inputs when this happens."),
),
Main(
P("To test, using FireFox, change the fields below then reload."),
H2("Form"),
Form(Class("box"),
//
// Text
//
Div(
Label("Text"),
Br(),
Input(Type("text"),
l.On("input", func(_ context.Context, e l.Event) {
if !e.IsInitial {
formValsNoSync[0].Set(e.Value)
}
formValsSync[0].Set(e.Value)
}),
),
),
//
// Password
//
Div(
Label("Password"),
Br(),
Input(Type("password"),
l.On("input", func(_ context.Context, e l.Event) {
if !e.IsInitial {
formValsNoSync[1].Set(e.Value)
}
formValsSync[1].Set(e.Value)
})),
),
//
// Range
//
Div(
Label("Range"),
Br(),
Input(Type("range"), Min("0"), Max("1000"),
l.On("input", func(_ context.Context, e l.Event) {
if !e.IsInitial {
formValsNoSync[2].Set(e.Value)
}
formValsSync[2].Set(e.Value)
}),
),
),
//
// Multi select
//
Div(
Label("Multi Select"),
Br(),
Select(Multiple(""),
l.On("input", func(_ context.Context, e l.Event) {
if !e.IsInitial {
formValsNoSync[3].Set(strings.Join(e.Values, ", "))
}
formValsSync[3].Set(strings.Join(e.Values, ", "))
}),
Option(Value("dog"), "Dog"),
Option(Value("cat"), "Cat"),
Option(Value("bird"), "Bird"),
Option("Fox"),
),
Br(),
Small("Click + Ctl/Cmd to multi select"),
),
//
// Radio
//
Div(
Label("Radio"),
Br(),
Label(For("radio_1"),
Input(
Type("radio"), Name("radio"), Value("orange"), Id("radio_1"),
l.On("input", func(_ context.Context, e l.Event) {
if !e.IsInitial {
formValsNoSync[4].Set(e.Value)
}
formValsSync[4].Set(e.Value)
}),
),
" Orange"),
Label(For("radio_2"),
Input(
Type("radio"), Name("radio"), Value("grape"), Id("radio_2"),
l.On("input", func(_ context.Context, e l.Event) {
if !e.IsInitial {
formValsNoSync[4].Set(e.Value)
}
formValsSync[4].Set(e.Value)
}),
),
" Grape"),
Label(For("radio_3"),
Input(
Type("radio"), Name("radio"), Value("lemon"), Id("radio_3"),
l.On("input", func(_ context.Context, e l.Event) {
if !e.IsInitial {
formValsNoSync[4].Set(e.Value)
}
formValsSync[4].Set(e.Value)
}),
),
" Lemon"),
Label(For("radio_4"),
Input(
Type("radio"), Name("radio"), Value("apple"), Id("radio_4"),
l.On("input", func(_ context.Context, e l.Event) {
if !e.IsInitial {
formValsNoSync[4].Set(e.Value)
}
formValsSync[4].Set(e.Value)
}),
),
" Apple"),
),
//
// Checkbox
//
Div(
Label("Checkbox"),
Br(),
Label(For("checkbox_1"),
Input(Type("checkbox"), Value("north"), Id("checkbox_1"),
l.On("input", func(_ context.Context, e l.Event) {
formValsNoSync[5].Set("")
formValsSync[5].Set("")
if !e.IsInitial && e.Selected {
formValsNoSync[5].Set(e.Value)
}
if e.Selected {
formValsSync[5].Set(e.Value)
}
}),
),
"North"),
Label(For("checkbox_2"),
Input(Type("checkbox"), Value("east"), Id("checkbox_2"),
l.On("input", func(_ context.Context, e l.Event) {
formValsNoSync[6].Set("")
formValsSync[6].Set("")
if !e.IsInitial && e.Selected {
formValsNoSync[6].Set(e.Value)
}
if e.Selected {
formValsSync[6].Set(e.Value)
}
}),
),
"East"),
Label(For("checkbox_3"),
Input(Type("checkbox"), Value("south"), Id("checkbox_3"),
l.On("input", func(_ context.Context, e l.Event) {
formValsNoSync[7].Set("")
formValsSync[7].Set("")
if !e.IsInitial && e.Selected {
formValsNoSync[7].Set(e.Value)
}
if e.Selected {
formValsSync[7].Set(e.Value)
}
}),
),
"South"),
Label(For("checkbox_4"),
Input(Type("checkbox"), Value("west"), Id("checkbox_4"),
l.On("input", func(_ context.Context, e l.Event) {
formValsNoSync[8].Set("")
formValsSync[8].Set("")
if !e.IsInitial && e.Selected {
formValsNoSync[8].Set(e.Value)
}
if e.Selected {
formValsSync[8].Set(e.Value)
}
}),
),
"West"),
),
),
//
// Output
//
H2("Server Side Data"),
Table(
Thead(
Tr(
Th(""),
Th("Sync"),
Th("No Sync"),
),
),
Tbody(
Tr(
Td("Text"),
Td(formValsSync[0]),
Td(formValsNoSync[0]),
),
Tr(
Td("Password", Br(),
Small("Browsers won't keep this on refresh")),
Td(formValsSync[1]),
Td(formValsNoSync[1]),
),
Tr(
Td("Range", Br(),
Small("Browsers set this to the mid point by default")),
Td(formValsSync[2]),
Td(formValsNoSync[2]),
),
Tr(
Td("Multi Select"),
Td(formValsSync[3]),
Td(formValsNoSync[3]),
),
Tr(
Td("Radio"),
Td(formValsSync[4]),
Td(formValsNoSync[4]),
),
Tr(
Td("Checkbox"),
Td(
formValsSync[5], " ", formValsSync[6], " ", formValsSync[7], " ", formValsSync[8]),
Td(
formValsNoSync[5], " ", formValsNoSync[6], " ", formValsNoSync[7], " ", formValsNoSync[8]),
),
),
),
),
)
return page
}