File Upload
Inspect a file before uploading it, then trigger the upload from the server.
File Upload
Use a file input to get information about a file before uploading it. Then trigger a file upload from the server when you're ready.
The file is uploaded via WebSocket as a binary (not base64 encoded) object.
Live Demo
Source
package examples
import (
"context"
"encoding/base64"
"fmt"
l "github.com/SamHennessy/hlive"
. "github.com/SamHennessy/hlive/hhtml"
)
// This live demo is public and always-on, so uploads are capped to keep a
// visitor from exhausting server memory (the original example holds the
// whole file in memory, which is fine for a local, single-user run).
const maxUploadBytes = 5 * 1024 * 1024 // 5 MB
// FileUploadDemo is a live, interactive instance of the File Upload example,
// served for the "Live Demo" iframe.
func FileUploadDemo() *l.Page {
var (
file = l.NewLockBox(l.File{})
fileName = l.Box("")
fileType = l.Box("")
fileSize = l.Box(0)
uploadError = l.Box("")
tableDisplay = l.NewLockBox("none")
fileDisplay = l.NewLockBox("none")
)
page := l.NewPage()
page.DOM().Title().Add("File Upload Example")
page.DOM().Head().Add(Link(Rel("stylesheet"), Href("https://cdn.simplecss.org/simple.min.css")))
iframe := Iframe(l.Style{"width": "100%", "height": "80vh"})
// Forced to a Component (rather than the hhtml Input() tag builder)
// because its upload/change bindings are attached after creation.
fileInput := l.C("input", Type("file"))
fileInput.Add(
l.On("upload", func(ctx context.Context, e l.Event) {
file.Lock(func(v l.File) l.File {
if len(e.File.Data) > maxUploadBytes {
uploadError.Set(fmt.Sprintf(
"This live demo caps uploads at %d MB. Run the example locally to try a larger file.",
maxUploadBytes/1024/1024))
fileInput.RemoveAttributes(l.AttrUpload)
return v
}
uploadError.Set("")
// This is a bad idea, using as an easy demo.
// The file is kept in server-side browser DOM using memory.
src := fmt.Sprintf("data:%s;base64,%s", e.File.Type,
base64.StdEncoding.EncodeToString(e.File.Data))
iframe.Add(Src(src))
fileDisplay.Set("box")
fileInput.RemoveAttributes(l.AttrUpload)
return *e.File
})
}),
l.On("change", func(ctx context.Context, e l.Event) {
if e.File != nil {
file.Lock(func(v l.File) l.File {
v = *e.File
fileName.Set(v.Name)
fileType.Set(v.Type)
fileSize.Set(v.Size)
tableDisplay.Set("box")
return v
})
}
}),
)
uploadBtn := Button("Upload",
l.On("click", func(ctx context.Context, e l.Event) {
if fileSize.Get() > maxUploadBytes {
uploadError.Set(fmt.Sprintf(
"This live demo caps uploads at %d MB. Run the example locally to try a larger file.",
maxUploadBytes/1024/1024))
return
}
fileInput.Add(l.Attrs{l.AttrUpload: ""})
}),
)
page.DOM().Body().Add(
Header(
H1("Upload"),
P("Example of using the file upload features."),
),
Main(
P(
fileInput,
uploadBtn,
),
P(l.Style{"color": "red"}, uploadError),
Div(l.StyleLockBox{"display": tableDisplay},
Table(
Tbody(
Tr(
Td("Name"), Td(fileName),
),
Tr(
Td("Type"), Td(fileType),
),
Tr(
Td("Size"), Td(I(fileSize), " bytes"),
),
),
),
),
Div(l.StyleLockBox{"display": fileDisplay},
H3("Uploaded File"),
Hr(),
iframe,
),
),
)
return page
}