YEW Tutorial: 03 Services and all
Tags: rust, yew, webassembly
Published: 2020-05-10 14:45:05

Good things come to those who wait... (PS: Photo by Kate Townsend on Unsplash)

We keep on extending... With services and more.

# Part 1: Intro to dirty talking (to the console)

### Code to follow this tutorial

The code has been tagged with the relative tutorial and part.

```Bash
git clone https://github.com/davidedelpapa/yew-tutorial.git
cd yew-tutorial
git checkout tags/v3p1a
```

I know you have been following me so far. So apart from typos, and some missing dependencies, I hope you have done well so far. Your only concern so far has been to copy and understand the code. What if you had to do it from scratch yourself? I've been doing the old programmer's way: try and error.

So it's time to talk a little about debugging. Speaking of which, debugging WASM is not that easy, so as all lazy programmers I try first the easy way around: printing and logging!

In javascript it's easy:

```javascript
console.log("Something's happening");
```

We log straight to the [console](https://developer.mozilla.org/en-US/docs/Web/API/Console).
This is the equivalent of our trusty `println!` used for the same debug purposes, but on the terminal (really the `stdout`).
What about Yew?

We start by `use`-ing the appropriate module in _app.rs_

```Rust
use rand::prelude::*;
use yew::prelude::*;
use yew::services::ConsoleService;
```

Then we need to update our _App_ struct:

```Rust
pub struct App {
    items: Vec<i64>,
    link: ComponentLink<Self>,
    console: ConsoleService,
}
```

Never forget to update our constructor, the _create_ fn:

```Rust
    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
        App {
            link,
            items: Vec::new(),
            console: ConsoleService::new(),
        }
    }
```

Now we can use our trusty console, just as we would in JS:

```Rust

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        match msg {
            Msg::AddOne => {
                let added: i64 = random();
                self.items.push(added);
                self.console.log(format!("Added {}", added).as_str());
            }
            Msg::RemoveOne => {
                let removed = self.items.pop();
                self.console
                    .log(format!("Removed {}", removed.unwrap_or_default()).as_str());
            }
        }
        true
    }
```

There is not much to that code, but we just rearranged last tutorial's code to have the random element to add in a variable to show, and we saved the popped element to show as well (using `unwrap_or_default` to handle the option)

Upon running we should see the JavaScript console being logged.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/sdm98s5ezr9290go0d9x.jpg)

As you can see it is _bundle.js_ the one who is actually logging to the JS console, because _bundle.js_ is where our WASM worker is called into play.

Coming up, another, better, way to log.

#### Code to follow this part

```Bash
git checkout tags/v3p1b
```

Raw logging to the console is a very primitive method. We love our wine, we love our luxuries, and we love our logging levels as well, don't we?
In fact, we can provide our WASM front-end and workers with the ability to log different levels of suspicious activities for debugging purposes

We can issue an [info](https://docs.rs/yew/0.14.2/yew/services/console/struct.ConsoleService.html#method.info):

```Rust
self.console.info("Added 1 elemet to the vec");
```

We can issue a [warning](https://docs.rs/yew/0.14.2/yew/services/console/struct.ConsoleService.html#method.warn), or we can even issue a more severe [error](https://docs.rs/yew/0.14.2/yew/services/console/struct.ConsoleService.html#method.error)

```Rust
let removed = self.items.pop();
match removed {
    Some(x) => self.console.warn(format!("Removed {}", x).as_str()),
    None => self.console.error("No more elements to remove!"),
};
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/k35fqcb2uisirewh0ch4.jpg)

Of course we can delve a little deeper and discover some more interesting stuff, like set a counter (to see how many times a certain part of a loop has been called, for example), or set timers, to record elapsed time. You can also clear the console, group and un-group with a level of indentation, and, better still: trace the calls and make JavaScript asserts. Maybe one day I'll write a tutorial on the subject.

Reference documentation is found on the [ConsoleService documentation](https://docs.rs/yew/0.14.2/yew/services/console/struct.ConsoleService.html).

# Part 2: some more dirty talk

#### Code to follow this part

```Bash
git checkout tags/v3p2a
```

Lowering ourselves in the realm of services, we find a handy little service: a dialog.

This service corresponds really to 2 modal windows: [alert](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert), and [confirm](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm). Modal widows steal the focus out of the current page, so they must be used wisely.

### Alert

The alert is just a small window with a message and an OK button. It just really shows to the user important stuff, stealing the focus from the page. Thus we will test it on a trivial case, just to bother our user.
Well, really just because right now there's nothing really important to communicate, it's just for the sake of showing the modal.

In our _src/app.rs_ we need first to update the services' `use` line:

```Rust
use yew::services::{ConsoleService, DialogService};
```

Then we need to update our _App_ struct, and our constructor, as usual:

```Rust
pub struct App {
    items: Vec<i64>,
    link: ComponentLink<Self>,
    console: ConsoleService,
    dialog: DialogService,
}
```

```Rust
    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
        App {
            link,
            items: Vec::new(),
            console: ConsoleService::new(),
            dialog: DialogService::new(),
        }
    }
```

Now, just to be less frivolous than expected (I know you were thinking of updating the error log with a dialog prompting the f\*ing user to stop deleting stuff when the list is empty; however, we are nice towards our users, aren't we?)

```Rust
pub enum Msg {
    AddOne,
    RemoveOne,
    About,
}
```

Now you do have a feeling of where I'm headed with this, don't ya?

```Rust
<header>
    <h2>{"Items: "}</h2>
    <button onclick=self.link.callback(|_| Msg::About)>{ "About" }</button>
</header>
```

With our trusty useless modal now showing

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6sjyc8bdppla0scmaahe.jpg)

How did we get that dialogue? With this one-line addition to the _Msg_ processing logic

```Rust
Msg::About => self.dialog.alert("Purposeless App"),
```

Just that! How cool is it?

### Confirm

#### Code to follow this part

```Bash
git checkout tags/v3p2b
```

The `Confirm` dialogue is actually the less useless of the two modals, since it returns something: it is a dialogue that steals the focus from the page, and shows a message with an `OK` and a `CANCEL` button. It returns a bool, with true meaning OK, **false all other cases**.

I know you are thinking: there are two cases, really, so what's wrong with saying false for `CANCEl`? well, if the browser is set to ignore in-page dialogs, then cofirm returns also false, without asking any question.

Well, let's add an action, in the most useless place...

```Rust
match removed {
    Some(x) => self.console.warn(format!("Removed {}", x).as_str()),
    None => {
        self.console.error("No more elements to remove!");
        let user_is_a_monkey = self
            .dialog
            .confirm("Are you dum? There are no more elements to remove!");
        if user_is_a_monkey {
            self.dialog.alert("I kenw it!");
        } else {
            self.dialog.alert(
                "Maybe it was an error, there are no more elements to remove!",
            );
        }
    }
};
```

And.. run!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/19yinewu5ozi0xq76tjh.jpg)

(PS: dum is not a word, or is it?)

As I was saying, after the first dialogue, Firefox shows a tick box in the modal.
If you mark it, the page will not show any more modals, thus the value of the `confirm` will always be `false` even if not showing.

We can _confirm_ this behavior of `confirm`, by logging the value of `user_is_a_monkey`

```Rust
match removed {
    Some(x) => self.console.warn(format!("Removed {}", x).as_str()),
    None => {
        self.console.error("No more elements to remove!");
        let user_is_a_monkey = self
            .dialog
            .confirm("Are you dum? There are no more elements to remove!");
        self.console
            .debug(format!("Confirm value: {}", user_is_a_monkey).as_str());
    }
};
```

As we can see if we select the tick to the _don't bother me_ mode, we log `false`s even though the dialog's not showing up!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/x9v8zd71eo9udw0ghi7s.jpg)

To get this on the console, I chose not to be bothered, and kept pushing `remove`: no dialogue appeared, yet it logged a `false`!

We must then remember this possible behavior and plan ahead.

For today it's all, we will continue in the next installment of this tutorial talking about more services. I promise you, they will be more useful than these Dialog modals, so stay tuned in!