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