mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
file upload example
This commit is contained in:
parent
1f017a2ade
commit
7d114c7414
2 changed files with 73 additions and 14 deletions
|
@ -27,6 +27,7 @@ thiserror = "1.0"
|
|||
wasm-bindgen = "0.2"
|
||||
serde_toml = "0.0.1"
|
||||
toml = "0.8.8"
|
||||
web-sys = { version = "0.3.67", features = ["FileList", "File"] }
|
||||
|
||||
[features]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
|
|
|
@ -1,23 +1,16 @@
|
|||
use crate::error_template::ErrorTemplate;
|
||||
use http::{Request, Response};
|
||||
use leptos::{html::Input, *};
|
||||
use leptos_meta::{Link, Stylesheet};
|
||||
use leptos_router::*;
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use server_fn::{
|
||||
codec::{
|
||||
Encoding, FromReq, FromRes, GetUrl, IntoReq, IntoRes, Rkyv, SerdeLite,
|
||||
},
|
||||
error::NoCustomError,
|
||||
request::{browser::BrowserRequest, BrowserMockReq, ClientReq, Req},
|
||||
response::{browser::BrowserResponse, ClientRes, Res},
|
||||
rkyv::AlignedVec,
|
||||
use leptos_meta::{provide_meta_context, Link, Stylesheet};
|
||||
use leptos_router::{ActionForm, Route, Router, Routes};
|
||||
use server_fn::codec::{
|
||||
GetUrl, MultipartData, MultipartFormData, Rkyv, SerdeLite,
|
||||
};
|
||||
#[cfg(feature = "ssr")]
|
||||
use std::sync::{
|
||||
atomic::{AtomicU8, Ordering},
|
||||
Mutex,
|
||||
};
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::{FormData, HtmlFormElement, SubmitEvent};
|
||||
|
||||
#[component]
|
||||
pub fn TodoApp() -> impl IntoView {
|
||||
|
@ -49,7 +42,7 @@ pub fn HomePage() -> impl IntoView {
|
|||
<h2>"Alternative Encodings"</h2>
|
||||
<ServerFnArgumentExample/>
|
||||
<RkyvExample/>
|
||||
<CustomEncoding/>
|
||||
<FileUpload/>
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -310,3 +303,68 @@ pub fn RkyvExample() -> impl IntoView {
|
|||
</Transition>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn FileUpload() -> impl IntoView {
|
||||
/// A simple file upload function, which does just returns the length of the file.
|
||||
///
|
||||
/// On the server, this uses the `multer` crate, which provides a streaming API.
|
||||
#[server(
|
||||
input = MultipartFormData,
|
||||
)]
|
||||
pub async fn file_length(
|
||||
data: MultipartData,
|
||||
) -> Result<usize, ServerFnError> {
|
||||
// `.into_inner()` returns the inner `multer` stream
|
||||
// it is `None` if we call this on the client, but always `Some(_)` on the server, so is safe to
|
||||
// unwrap
|
||||
let mut data = data.into_inner().unwrap();
|
||||
|
||||
// this will just measure the total number of bytes uploaded
|
||||
let mut count = 0;
|
||||
while let Ok(Some(mut field)) = data.next_field().await {
|
||||
println!("\n[NEXT FIELD]\n");
|
||||
let name = field.name().unwrap_or_default().to_string();
|
||||
println!(" [NAME] {name}");
|
||||
while let Ok(Some(chunk)) = field.chunk().await {
|
||||
let len = chunk.len();
|
||||
count += len;
|
||||
println!(" [CHUNK] {len}");
|
||||
// in a real server function, you'd do something like saving the file here
|
||||
}
|
||||
}
|
||||
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
let upload_action = create_action(|data: &FormData| {
|
||||
let data = data.clone();
|
||||
// `MultipartData` implements `From<FormData>`
|
||||
file_length(data.into())
|
||||
});
|
||||
|
||||
view! {
|
||||
<h3>File Upload</h3>
|
||||
<p>Uploading files is fairly easy using multipart form data.</p>
|
||||
<form on:submit=move |ev: SubmitEvent| {
|
||||
ev.prevent_default();
|
||||
let target = ev.target().unwrap().unchecked_into::<HtmlFormElement>();
|
||||
let form_data = FormData::new_with_form(&target).unwrap();
|
||||
upload_action.dispatch(form_data);
|
||||
}>
|
||||
<input type="file" name="file_to_upload"/>
|
||||
<input type="submit"/>
|
||||
</form>
|
||||
<p>
|
||||
{move || if upload_action.input().get().is_none() && upload_action.value().get().is_none() {
|
||||
"Upload a file.".to_string()
|
||||
} else if upload_action.pending().get() {
|
||||
"Uploading...".to_string()
|
||||
} else if let Some(Ok(value)) = upload_action.value().get() {
|
||||
value.to_string()
|
||||
} else {
|
||||
format!("{:?}", upload_action.value().get())
|
||||
}}
|
||||
</p>
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue