macro_rules! impl_section {
($name:ident, $json:ty, $patch_json:ty, $url:expr, $($element:ident),*) => { ... };
}
Expand description
UI macro: implements a REST API section with default functionality.
This UI macro calls impl_section_custom
and
it additionally calls the following macros to define dummy user-provided
functions that do nothing:
-
impl_post_update_noop
, which implements a dummypost_update_name_elements
method. -
impl_post_patch_update_elements_noop
, which implements a dummypost_patch_name_update_elements
method. -
impl_onchange_patch_modify_noop
, which implements a dummyname_onchange_patch_modify
method.
If custom functionality needs to be used in any of these methods,
impl_section_custom
needs to be used instead of impl_section
. The
impl_*_noop
macros can still be called to implement the methods that do
not need custom functionality.
§Example
§Example
use maia_wasm::{impl_dummy_preferences, impl_section, set_on, ui_elements, ui::input::NumberInput};
use serde::{Deserialize, Serialize};
use std::{cell::RefCell, rc::Rc};
use wasm_bindgen::JsValue;
use web_sys::{Document, HtmlInputElement, Window};
// An object defined by a REST API. This corresponds to the GET method.
#[derive(Debug, Clone, Serialize, Deserialize)]
struct MyObject {
my_integer: u64,
my_float: f32,
}
// An object defined by a REST API. This corresponds to the PATCH method.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
struct PatchMyObject {
#[serde(skip_serializing_if = "Option::is_none")]
my_integer: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
my_float: Option<f32>,
}
#[derive(Clone)]
struct Ui {
window: Rc<Window>,
document: Rc<Document>,
elements: Elements,
// the api_state is optional; it could be defined
// as Rc<RefCell<Option<()>> and set to contain None
api_state: Rc<RefCell<Option<ApiState>>>,
preferences: Rc<RefCell<Preferences>>,
}
ui_elements! {
my_object_my_integer: HtmlInputElement => NumberInput<u64>,
my_object_my_float: HtmlInputElement => NumberInput<f32>,
}
struct ApiState {
my_object: MyObject,
}
// Dummy Preferences struct. This is needed because update_elements
// keeps the preferences in sync, so it calls methods in the Preferences.
struct Preferences {}
impl_dummy_preferences!(
my_object_my_integer: u64,
my_object_my_float: f32,
);
impl Ui {
fn new(window: Rc<Window>, document: Rc<Document>) -> Result<Ui, JsValue> {
let elements = Elements::new(&document)?;
let preferences = Rc::new(RefCell::new(Preferences {}));
let api_state = Rc::new(RefCell::new(Some(ApiState {
my_object: MyObject { my_integer: 0, my_float: 0.0 },
})));
let ui = Ui { window, document, elements, api_state, preferences };
ui.set_callbacks();
Ok(ui)
}
fn set_callbacks(&self) -> Result<(), JsValue> {
set_on!(change,
self,
my_object_my_integer,
my_object_my_float);
Ok(())
}
// it is necessary to define an alert method like this
// to show errors to the user
fn alert(&self, message: &str) -> Result<(), JsValue> {
self.window.alert_with_message(message);
Ok(())
}
impl_section!(my_object,
MyObject,
PatchMyObject,
"/my_object",
my_integer,
my_float);
}