Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File engine documentation #102

Merged
merged 5 commits into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs-src/0.4/en/reference/user_input.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,28 @@ DemoFrame {
```
Submitted! UiEvent { data: FormData { value: "", values: {"age": "very old", "date": "1966", "name": "Fred"} } }
```

## Handling files
You can insert a file picker by using an input element of type `file`. This element supports the `multiple` attribute, to let you pick more files at the same time. You can select a folder by adding the `directory` attribute: Dioxus will map this attribute to browser specific attributes, because there is no standardized way to allow a directory to be selected.

`type` is a Rust keyword, so when specifying the type of the input field, you have to write it as `r#type:"file"`.

Extracting the selected files is a bit different from what you may typically use in Javascript.

The `FormData` event contains a `files` field with data about the uploaded files. This field contains a `FileEngine` struct which lets you fetch the filenames selected by the user. This example saves the filenames of the selected files to a `Vec`:

```rust, no_run
{{#include src/doc_examples/input_fileengine.rs:component}}
```

If you're planning to read the file content, you need to do it asynchronously, to keep the rest of the UI interactive. This example event handler loads the content of the selected files in an async closure:

```rust, no_run
{{#include src/doc_examples/input_fileengine_async.rs:onchange_event}}
```

Lastly, this example shows you how to select a folder, by setting the `directory` attribute to `true`.

```rust, no_run
{{#include src/doc_examples/input_fileengine_folder.rs:rsx}}
```
28 changes: 28 additions & 0 deletions src/doc_examples/input_fileengine.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#![allow(non_snake_case)]
use dioxus::prelude::*;

// ANCHOR: component
pub fn App(cx: Scope) -> Element {
// ANCHOR: rsx
let filenames: &UseRef<Vec<String>> = use_ref(cx, Vec::new);
cx.render(rsx! {
input {
// tell the input to pick a file
r#type:"file",
// list the accepted extensions
accept: ".txt, .rs",
// pick multiple files
multiple: true,
onchange: |evt| {
if let Some(file_engine) = &evt.files {
let files = file_engine.files();
for file_name in &files {
filenames.write().push(file_name);
}
}
}
}
})
// ANCHOR_END: rsx
}
// ANCHOR_END: component
34 changes: 34 additions & 0 deletions src/doc_examples/input_fileengine_async.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#![allow(non_snake_case)]
use dioxus::prelude::*;

// ANCHOR: component
pub fn App(cx: Scope) -> Element {
let files_uploaded: &UseRef<Vec<String>> = use_ref(cx, Vec::new);

cx.render(rsx! {
input {
r#type:"file",
accept: ".txt, .rs",
multiple: true,
// ANCHOR: onchange_event
onchange: |evt| {
// A helper macro to use hooks in async environments
to_owned![files_uploaded];
async move {
if let Some(file_engine) = &evt.files {
let files = file_engine.files();
for file_name in &files {
// Make sure to use async/await when doing heavy I/O operations,
// to not freeze the interface in the meantime
if let Some(file) = file_engine.read_file_to_string(file_name).await{
files_uploaded.write().push(file);
}
}
}
}
}
// ANCHOR_END: onchange_event
}
})
}
// ANCHOR_END: component
26 changes: 26 additions & 0 deletions src/doc_examples/input_fileengine_folder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#![allow(non_snake_case)]
use dioxus::prelude::*;

// ANCHOR: component
pub fn App(cx: Scope) -> Element {
let filenames: &UseRef<Vec<String>> = use_ref(cx, Vec::new);
cx.render(rsx! {
// ANCHOR: rsx
input {
r#type:"file",
// Select a folder by setting the directory attribute
directory: true,
onchange: |evt| {
if let Some(file_engine) = &evt.files {
let files = file_engine.files();
for file_name in &files {
println!("{}", file_name);
// Do something with the folder path
}
}
}
}
// ANCHOR_END: rsx
})
}
// ANCHOR_END: component
Loading