zng/
data_context.rs

1#![cfg(feature = "data_context")]
2
3//! Data context service and properties.
4//!
5//! The [`data`](fn@data) property can be set on a widget to any type that can be used in variables ([`VarValue`]). The
6//! [`DATA`] service can then be used on the widget or descendant widgets to retrieve the data and to set validation annotations
7//! about the data.
8//!
9//! The example below demonstrates a simple [MVVM] implementation using the data context to share the view-model instance
10//! with all widgets in the view. The example also uses the data annotations API to show data validation errors.
11//!
12//! [MVVM]: https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel
13//!
14//! ```
15//! # fn main() { }
16//! mod view {
17//!     use crate::view_model::*;
18//!     use zng::{data_context, prelude::*, window::WindowRoot};
19//!
20//!     pub fn window() -> WindowRoot {
21//!         Window! {
22//!             // set data context for entire window, using `var` to be read-write.
23//!             data = var(ViewModel::new(crate::model::connect()));
24//!
25//!             // bind title from data context.
26//!             title = DATA.req::<ViewModel>().map(|vm| vm.title());
27//!             child = content();
28//!         }
29//!     }
30//!
31//!     fn content() -> impl UiNode {
32//!         // `req` panics if context is not set to the same type.
33//!         let vm = DATA.req::<ViewModel>();
34//!         Container! {
35//!             child = TextInput! {
36//!                 txt = vm.map_ref_bidi(|vm| vm.new_item(), |vm| vm.new_item_mut());
37//!
38//!                 // FieldStyle shows data errors.
39//!                 style_fn = style_fn!(|_| zng::text_input::FieldStyle!());
40//!                 data_context::data_error = vm.map_ref(|vm| vm.new_item_error());
41//!             };
42//!             child_bottom = Button! {
43//!                 child = Text!("Submit");
44//!                 widget::enabled = vm.map(|vm| !vm.new_item().is_empty());
45//!                 on_click = hn!(|_| vm.modify(|vm| vm.to_mut().submit()).unwrap());
46//!             }, 5;
47//!             padding = 5;
48//!         }
49//!     }
50//! }
51//!
52//! mod view_model {
53//!     use crate::model::Model;
54//!     use zng::text::*;
55//!
56//!     #[derive(Clone, Debug, PartialEq)]
57//!     pub struct ViewModel {
58//!         model: Model,
59//!         new_item: Txt,
60//!         new_item_error: Txt,
61//!     }
62//!     impl ViewModel {
63//!         pub fn new(model: Model) -> Self {
64//!             Self {
65//!                 model,
66//!                 new_item: Txt::from(""),
67//!                 new_item_error: Txt::from(""),
68//!             }
69//!         }
70//!
71//!         pub fn title(&self) -> Txt {
72//!             formatx!("App - {} entries", self.model.read().len())
73//!         }
74//!
75//!         pub fn new_item(&self) -> &Txt {
76//!             &self.new_item
77//!         }
78//!         pub fn new_item_mut(&mut self) -> &mut Txt {
79//!             self.new_item_error = Txt::from("");
80//!             &mut self.new_item
81//!         }
82//!
83//!         pub fn new_item_error(&self) -> &Txt {
84//!             &self.new_item_error
85//!         }
86//!
87//!         pub fn submit(&mut self) {
88//!             match self.new_item.parse::<u32>() {
89//!                 Ok(item) => {
90//!                     self.model.write().push(item);
91//!                     self.new_item_mut().clear();
92//!                 }
93//!                 Err(e) => self.new_item_error = e.to_txt(),
94//!             }
95//!         }
96//!     }
97//! }
98//!
99//! mod model {
100//!     use zng::{task::parking_lot::RwLock, var::ArcEq};
101//!
102//!     pub type Model = ArcEq<RwLock<Vec<u32>>>;
103//!
104//!     pub fn connect() -> ArcEq<RwLock<Vec<u32>>> {
105//!         ArcEq::new(RwLock::new(vec![]))
106//!     }
107//! }
108//! ```
109//!
110//! Note that vars clone the value when modify is requested, so the view-model should probably use shared
111//! references to the model data, overall this cloning has no noticeable impact as it only happens once
112//! per user interaction in the worst case.
113//!
114//! [`data`]: fn@data
115//! [`VarValue`]: crate::var::VarValue
116//!
117//! # Full API
118//!
119//! See [`zng_wgt_data`] for the full API.
120
121pub use zng_wgt_data::{
122    DATA, DataNote, DataNoteHandle, DataNoteLevel, DataNoteValue, DataNotes, data, data_error, data_error_color, data_info,
123    data_info_color, data_note, data_warn, data_warn_color, extend_data_note_colors, get_data_error, get_data_error_txt, get_data_info,
124    get_data_info_txt, get_data_notes, get_data_notes_top, get_data_warn, get_data_warn_txt, has_data_error, has_data_info, has_data_notes,
125    has_data_warn, replace_data_note_colors, with_data_note_color,
126};