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