impl_section

Macro impl_section 

Source
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:

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);
}