Reading and uploading files
Files chosen in a file input come in the on_change_file event, and files dropped onto an element in the on_dropfile event. Both give a DropFileEvent with a list of files, each having a name and the whole content in data:
use vertigo::{bind, css, dom, DropFileEvent, Value}; let files = Value::new(Vec::<String>::new()); // The same handler for both the file input and the drop zone let add_files = bind!(files, |event: DropFileEvent| { files.change(|files| { for file in event.items { // file.data contains the whole file content files.push(format!("{} ({} bytes)", file.name, file.data.len())); } }) }); let drop_zone_css = css! {" padding: 20px; border: 2px dashed gray; "}; let list = files.render_value(|files| { dom! { <ul>{..files.into_iter().map(|file| dom! { <li>{file}</li> })}</ul> } }); dom! { <div> <input type="file" multiple="multiple" on_change_file={add_files.clone()} /> <div css={drop_zone_css} on_dropfile={add_files}>"...or drop files here"</div> {list} </div> }
Uploading
RequestBuilder sends request bodies as JSON, so the file content needs to be encoded, usually with base64. The ImageUpload struct from vertigo-forms does that for images:
use vertigo::{bind, dom, get_driver, DropFileEvent, RequestBuilder, Value}; use vertigo_forms::ImageUpload; let status = Value::new(String::new()); let upload = bind!(status, |event: DropFileEvent| { let Some(file) = event.items.into_iter().next() else { return; }; status.set(format!("Uploading {}...", file.name)); get_driver().spawn(bind!(status, async move { // Name, mime type and base64-encoded content let image = ImageUpload::from(file); let response = RequestBuilder::post("/api/avatar") .body_json(image) .call() .await; status.set(match response.status() { Some(200) => "Uploaded".to_string(), _ => "Upload failed".to_string(), }); })); }); dom! { <div> <input type="file" accept="image/*" on_change_file={upload} /> <p>{status}</p> </div> }
For other kinds of files, put the content encoded with the base64 crate into a field of your own struct.