DOM events and state

Interacting with the DOM#

When building your dashboard you may want to add some functionality to the UI. This is easily done by utilizing special assemble- prefixed attributes in your HTML tags.

a href="#" assemble-click="i-was-clicked" assemble-value-my_param="I will be a param" {
"Click me!"
}

When these events trigger, they call the local_event function on your View. This method is called with a msg and payload argument. The msg is a text string to match on. The payload is a MsgPack encoded datastructure corrosponding to the event. The payload can be build using a form or the assemble-value-* attribute.

#[derive(Deserialize, Serialize)]
struct MyClickEvent {
my_param: String,
}
// ...
impl View for ViewHandler {
// ..
fn local_event(&mut self, msg: &str, payload: &[u8]) -> Result<()> {
match msg {
"i-was-clicked" => {
let item: MyClickEvent = deserialize?(payload);
// Do something
Ok(())
}
_ => Ok(())
}
}
}

List of attributes#

A list of available attributes are available here. Please refer to the LiveView docs on their phoenix equivalent for more details (simply replace assemble- prefix with phx-)

BindingAttributes
Paramsassemble-value-*
Click Eventsassemble-click, assemble-capture-click
Focus/Blur Eventsassemble-blur, assemble-focus, assemble-window-blur, assemble-window-focus
Key Eventsassemble-keydown, assemble-keyup, assemble-window-keydown, assemble-window-keyup, assemble-key
Form Eventsassemble-change, assemble-submit, assemble-feedback-for, assemble-disable-with, assemble-trigger-action, assemble-auto-recover
Rate Limitingassemble-debounce, assemble-throttle
DOM Patchingassemble-update

Changing your view's state#

Your view must implement the Deserialize and Serialize traits from serde. After an event, your view's state is serialized using MsgPack until the next event that comes in. This allows you to create stateful apps by simply mutating your View's attributes.

See the limits section for additional information about this serialization.

Rendering Dynamic Content#

Content can be built up using normal Rust programming in your render method. See maud's documentation about how to incorporate control structures into your app.

Putting it together#

Combining DOM events, stateful views and dynamic content, we can create an app which updates based on a click.

Quick view for details and to fork.

extern crate assemble_app;
extern crate serde;
extern crate maud;
use assemble_app::*;
use maud::html;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap};
assemble_init! {{
register_root_view!(ViewHandler);
}}
#[derive(Deserialize, Serialize)]
struct ViewHandler {
chosen_animal: String,
}
#[derive(Deserialize, Serialize)]
struct MyClickEvent {
animal: String,
}
impl View for ViewHandler {
fn start(_is_connected: bool, _params: HashMap<String, String>) -> Result<Self> {
Ok(ViewHandler {chosen_animal: "โ“".into()}).into()
}
fn render(&self) -> Result<Html> {
let markup = html! {
div class="bg-indigo-700" {
div class="max-w-2xl mx-auto text-center py-16 px-8" {
h2 class="cursor-pointer mt-4 text-3xl font-extrabold text-white" {
"You clicked: " (self.chosen_animal)
}
a href="#" assemble-click="i-was-clicked" assemble-value-animal="๐Ÿ•" class="cursor-pointer mt-4 mx-6 text-2xl font-extrabold text-white" {
"๐Ÿ•"
}
a href="#" assemble-click="i-was-clicked" assemble-value-animal="๐Ÿˆ" class="cursor-pointer mt-4 mx-6 text-2xl font-extrabold text-white" {
"๐Ÿˆ"
}
}
}
};
Ok(markup.into_string())
}
fn local_event(&mut self, msg: &str, payload: &[u8]) -> Result<()> {
match msg {
"i-was-clicked" => {
let ev: MyClickEvent = deserialize(payload)?;
self.chosen_animal = ev.animal;
Ok(())
}
_ => Ok(())
}
}
}