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 }