Skip to content

Commit 0102d62

Browse files
EnigoMadoshakalakakirillsemyonkin
authored
Add Function Delayed Input Processing Example (#3586)
Co-authored-by: Mattuwu <syan4@ualberta.ca> Co-authored-by: Kirill <burnytc@gmail.com>
1 parent 741849d commit 0102d62

6 files changed

Lines changed: 137 additions & 0 deletions

File tree

Cargo.lock

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ As an example, check out the TodoMVC example here: <https://examples.yew.rs/todo
4141
| [counter_functional](counter_functional) | [F] | Simple counter which can be incremented and decremented made using function components. |
4242
| [dyn_create_destroy_apps](dyn_create_destroy_apps) | [S] | Uses the function `Renderer::with_root_and_props` and the `AppHandle` struct to dynamically create and delete Yew apps. |
4343
| [file_upload](file_upload) | [S] | Uses [`gloo::file`](https://docs.rs/gloo-file/latest/gloo_file/index.html) to read the content of user uploaded files. |
44+
| [function_delayed_input](function_delayed_input) | [F] | Demonstrates how to implement a form with delayed input processing. |
4445
| [function_memory_game](function_memory_game) | [F] | Implementation of [Memory Game](https://github.com/bradlygreen/Memory-Game). |
4546
| [function_router](function_router) | [F] | Identical to [`router`](router) but using function components. |
4647
| [function_todomvc](function_todomvc) | [F] | Implementation of [TodoMVC](http://todomvc.com/) using function components and hooks. |
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "function_delayed_input"
3+
version = "0.1.0"
4+
authors = ["Ruslan Sibgatullin <info@pudding.pro>"]
5+
edition = "2021"
6+
license = "MIT OR Apache-2.0"
7+
8+
[dependencies]
9+
gloo-timers = { version = "0.3.0", features = ["futures"] }
10+
web-sys = { version = "0.3.67", features = ["Window"]}
11+
yew = { path = "../../packages/yew", features = ["csr"] }
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Delayed Input Processing Example
2+
3+
[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Ffunction_delayed_input)](https://examples.yew.rs/function_delayed_input)
4+
5+
This is a demonstration of how to create an input form with delayed input processing.
6+
7+
A typical use case is to send user input to the backend only when they have stopped typing, rather than on every keystroke.
8+
9+
## Concepts
10+
- Uses [`gloo-timers`](https://crates.io/crates/gloo-timers) to delay the processing
11+
12+
## Running
13+
14+
Run this application with the trunk development server:
15+
16+
```bash
17+
trunk serve --open
18+
```
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8"/>
5+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
6+
<title>Yew • Function Delayed Input</title>
7+
8+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
9+
<link data-trunk rel="rust"/>
10+
</head>
11+
<body></body>
12+
</html>
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use std::time::Duration;
2+
3+
use gloo_timers::callback::Timeout;
4+
use web_sys::wasm_bindgen::JsCast;
5+
use web_sys::HtmlInputElement;
6+
use yew::*;
7+
8+
#[component]
9+
fn App() -> Html {
10+
#[derive(PartialEq, Default, Clone)]
11+
enum Search {
12+
#[default]
13+
Idle,
14+
Fetching(AttrValue),
15+
Fetched(AttrValue),
16+
}
17+
18+
let search = use_state(Search::default);
19+
20+
use_effect_with(search.clone(), {
21+
move |search| {
22+
// here you would typically do a REST call to send the search input to backend
23+
// for simplicity sake here we just set back the original input
24+
if let Search::Fetching(query) = &**search {
25+
yew::platform::spawn_local({
26+
let query = query.clone();
27+
let search = search.setter();
28+
async move {
29+
// Simulate a network delay
30+
gloo_timers::future::sleep(Duration::from_millis(500)).await;
31+
search.set(Search::Fetched(
32+
format!("Placeholder response for: {}", query).into(),
33+
));
34+
}
35+
});
36+
}
37+
}
38+
});
39+
40+
let oninput = {
41+
let timeout_ref = use_mut_ref(|| None);
42+
use_callback((), {
43+
let search = search.clone();
44+
move |e: InputEvent, _| {
45+
if let Some(target) = e.target() {
46+
let input = target.dyn_into::<HtmlInputElement>().ok();
47+
if let Some(input) = input {
48+
let value = input.value();
49+
if !value.is_empty() {
50+
let search = search.setter();
51+
let timeout = Timeout::new(1_000, move || {
52+
search.set(Search::Fetching(value.into()));
53+
});
54+
(*timeout_ref.borrow_mut()) = Some(timeout);
55+
}
56+
}
57+
}
58+
}
59+
})
60+
};
61+
62+
html! {
63+
<div class="container p-2">
64+
<div class="row">
65+
<div class="p-2">
66+
<form class="input-group bg-dark border border-white rounded">
67+
<input id="search" autocomplete="off" type="search" class="form-control" placeholder="Type something here..." aria-label="Search" {oninput}/>
68+
</form>
69+
</div>
70+
<div class="p-2 border border-black rounded">
71+
<p>{
72+
match &*search {
73+
Search::Idle => "Type something to search...".into(),
74+
Search::Fetching(query) => format!("Searching for: {}", query).into(),
75+
Search::Fetched(response) => response.clone(),
76+
}
77+
}</p>
78+
</div>
79+
</div>
80+
</div>
81+
}
82+
}
83+
84+
fn main() {
85+
yew::Renderer::<App>::new().render();
86+
}

0 commit comments

Comments
 (0)