Replies: 1 comment 4 replies
-
I have started converting https://github.com/yewstack/yew/blob/master/examples/file_upload/src/main.rs to yew-hooks but failed as gloo_files::File does not implement Clone and PartialEq here is code that would work if gloo_files::File gets fixed: use std::ops::Deref;
use gloo_file::File;
use wasm_bindgen_futures::spawn_local;
use web_sys::HtmlInputElement;
use yew::prelude::*;
#[derive(Clone, PartialEq, Properties)]
pub struct FileInputProps {
pub on_change: Callback<Vec<File>>,
}
#[function_component(FileInput)]
pub fn file_input(props: &FileInputProps) -> Html {
let FileInputProps { on_change } = props.clone();
let onchange = Callback::from(move |e: Event| {
let input: HtmlInputElement = e.target_unchecked_into();
if let Some(files) = input.files() {
on_change.emit(
js_sys::try_iter(&files)
.unwrap()
.unwrap()
.map(|value| web_sys::File::from(value.unwrap()))
.map(File::from)
.collect(),
)
}
});
html! {<input type="file" multiple=true {onchange} />}
}
async fn read_as_text(file: &File) -> String {
let (sender, receiver) = futures::channel::oneshot::channel::<String>();
gloo_file::callbacks::read_as_text(file, move |res| sender.send(res.unwrap()).unwrap());
receiver.await.unwrap()
}
async fn read_as_bytes(file: &File) -> Vec<u8> {
let (sender, receiver) = futures::channel::oneshot::channel::<Vec<u8>>();
gloo_file::callbacks::read_as_bytes(file, move |res| sender.send(res.unwrap()).unwrap());
receiver.await.unwrap()
}
fn convert_to_files_strings(files: Vec<File>, files_strings_handle: UseStateHandle<Vec<(String, String)>>) {
spawn_local(async move {
let file_names = files.iter().map(|file| file.name());
let blobs_strings = futures::future::join_all(files.iter().map(read_as_text)).await;
let files_strings: Vec<(String, String)> = file_names.zip(blobs_strings.into_iter()).collect();
files_strings_handle.set(files_strings);
});
}
fn convert_to_files_bytes(files: Vec<File>, files_bytes_handle: UseStateHandle<Vec<(String, Vec<u8>)>>) {
spawn_local(async move {
let file_names = files.iter().map(|file| file.name());
let blobs_bytes = futures::future::join_all(files.iter().map(read_as_bytes)).await;
let files_bytes: Vec<(String, Vec<u8>)> = file_names.zip(blobs_bytes.into_iter()).collect();
files_bytes_handle.set(files_bytes);
});
}
fn files_list_html<T: std::fmt::Debug>(files_data_list: Vec<(String, T)>) -> Html {
let list_items = files_data_list.into_iter().map(|(file_name, data)| {
html! {<li>{ format!("file_name: {}, data: {:?}", file_name, data) }</li>}
});
html! {<ul>{for list_items}</ul>}
}
#[function_component(App)]
pub fn app() -> Html {
let show_as_bytes_handle = use_state_eq(|| false);
let show_as_bytes = *show_as_bytes_handle;
let onclick = Callback::from(move |_| show_as_bytes_handle.set(!show_as_bytes));
let files_handle: UseStateHandle<Vec<File>> = use_state(Default::default);
let files = files_handle.deref().clone(); // impossible to move out of state until gloo_file::File implement Clone
let handle_files_input = Callback::from(move |files| files_handle.set(files));
let files_strings_handle: UseStateHandle<Vec<(String, String)>> = use_state(Default::default);
let files_strings: Vec<(String, String)> = files_strings_handle.deref().clone();
let files_bytes_handle: UseStateHandle<Vec<(String, Vec<u8>)>> = use_state(Default::default);
let files_bytes: Vec<(String, Vec<u8>)> = files_bytes_handle.deref().clone();
use_effect_with_deps(
{
let files = files.clone();
move |_| {
convert_to_files_strings(files.clone(), files_strings_handle);
convert_to_files_bytes(files, files_bytes_handle);
|| {}
}
},
files,
);
html! {
<>
<div>
<p>{ "Choose a file to upload to see the uploaded bytes" }</p>
<FileInput on_change={handle_files_input} />
</div>
<div>
<label>{ "Show as bytes" }</label>
<input type="checkbox" checked={show_as_bytes} {onclick} />
</div>
if !show_as_bytes {
// I would create a component <FilesStrings {files} />
// but currently files don't implement Clone and PartialEq so its impossible
{files_list_html(files_strings)}
} else {
{files_list_html(files_bytes)}
}
</>
}
} |
Beta Was this translation helpful? Give feedback.
4 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Hi,
How to display in log or in the web page the content of an uploaded textfile in functional comp style?
I'm able to get the file as a
web_sys::File
but struggling to deal with the actual content.Thanks
Beta Was this translation helpful? Give feedback.
All reactions