maxence-charriere / go-app

A package to build progressive web apps with Go programming language and WebAssembly.

Home Page:https://go-app.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

how to upload and access a file

rtrzebinski opened this issue · comments

Hi, I'm looking for a way to upload a (CSV) file, and access its content, what I have now:

app.Input().ID("csv-upload-button").Type("file").Name("csv-import.csv").Accept(".csv").OnInput(c.handleCsvUpload),

func (c *Exercises) handleCsvUpload(ctx app.Context, e app.Event) {
	app.Log("handleCsvUpload")

	// now what? :D
}

When I click the button the file is set in the browser, but not uploaded automatically. I know I could add a submit button, but ideally I'd like to:

  • auto upload the file once selected by the user
  • access this file in my app

Thank you.

Here's an option:

func (r *Exercises) handleCsvUpload(ctx app.Context, e app.Event) {
	// TODO:
	//  This does not handle multiple files.
	//  Validate file type which can be changed by the user in the file picker.

	file := e.Get("target").Get("files").Index(0)
	fmt.Println("name", file.Get("name").String())
	fmt.Println("size", file.Get("size").Int())
	fmt.Println("type", file.Get("type").String())

	if data, err := readFile(file); err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(string(data))
	}
}

func readFile(file app.Value) (data []byte, err error) {
	done := make(chan bool)

	// https://developer.mozilla.org/en-US/docs/Web/API/FileReader
	reader := app.Window().Get("FileReader").New()
	reader.Set("onloadend", app.FuncOf(func(this app.Value, args []app.Value) interface{} {
		done <- true
		return nil
	}))
	reader.Call("readAsArrayBuffer", file)
	<-done

	readerError := reader.Get("error")
	if !readerError.IsNull() {
		err = fmt.Errorf("file reader error : %s", readerError.Get("message").String())
	} else {
		uint8Array := app.Window().Get("Uint8Array").New(reader.Get("result"))
		data = make([]byte, uint8Array.Length())
		app.CopyBytesToGo(data, uint8Array)
	}
	return data, err
}

I wouldn't figure it out myself in a million years :D (not a frontend developer)

Works lika a charm, thank you so much Matt! @mlctrez

One more thing - I've made a change as suggested and it works fine -> rtrzebinski/simple-memorizer-4@96912ed

However it only works once, if I upload 2nd time, it does nothing.

When I refresh the page, it works again (again only once).

What should I do for it to work multiple times?

Perhaps the JS object needs to be reset somehow?

I tried:

c.Update()

but no effect 🤔

Added file input reset on last line of this method:

func (r *Exercises) handleCsvUpload(ctx app.Context, e app.Event) {
	// TODO:
	//  This does not handle multiple files.
	//  Validate file type which can be changed by the user in the file picker.

	file := e.Get("target").Get("files").Index(0)
	fmt.Println("name", file.Get("name").String())
	fmt.Println("size", file.Get("size").Int())
	fmt.Println("type", file.Get("type").String())

	if data, err := readFile(file); err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(string(data))
	}
	// reset file input for next upload
	e.Get("target").Set("value", "")
}

Perfect, thank you @mlctrez it helped :)