Cross Reference: /yui3/src/attribute/docs/attribute-event.mustache
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<style type="text/css" scoped>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai #example-out .event {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai padding:2px 2px 2px 5px;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai }
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai #example-out .event-props {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai font-family:courier;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai margin-top:2px;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai }
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai #example-out .event-title {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai font-weight:bold;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai font-family:arial;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai color:#8dd5e7;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai margin-top:5px;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai margin-bottom:3px;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai }
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai #example-out {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai margin:5px;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai border:1px solid #000;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai color:#ffffff;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai background-color:#004c6d;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai overflow:auto;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai height:20em;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai }
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai .attrs {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai border:1px solid #000;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai background-color:#cdcdcd;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai margin:5px;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai }
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai .attrs .header {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai font-weight:bold;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai background-color:#aaa;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai padding:5px;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai }
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai .attrs .body {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai padding:10px;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai }
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai .attrs .footer {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai padding:5px;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai }
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai .attrs label {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai display:block;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai float:left;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai clear:left;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai font-weight:bold;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai width:8em;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai }
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai .attrs #preventFoobar.hidden {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai display:none;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai }
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai .attrs #preventFoobar {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai margin-left:5px;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai display:inline;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai float:none;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai clear:none;
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai }
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai</style>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<div class="intro">
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai <p>Attribute change events are one of the key benefits of using attributes to maintain state for your objects, instead of regular object properties. This example shows how you can listen for attribute change events and work with the event payload they receive.</p>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai</div>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<div class="example">
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai {{>attribute-event-source}}
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai</div>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<h2>Listening For Attribute Change Events</h2>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<p>In this example, we'll look at how you can setup listeners for attribute change events, and work with the event payload which the listeners receive.</p>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<h3>Setting Up A Custom Class With Attribute</h3>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<p>We start by setting up the same custom class we created for the <a href="attribute-basic.html">basic example</a> with 3 attributes `foo`, `bar` and `foobar`, using the code below:</p>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai```
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen DesaiYUI().use("attribute", "node", function(Y) {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai // Setup a custom class with attribute support
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai function MyClass(cfg) {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai // Setup attribute configuration
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai var attrs = {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai "foo" : {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai value:5
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai },
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai "bar" : {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai value:"Hello World!"
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai },
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai "foobar" : {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai value:true
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai }
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai };
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai this.addAttrs(attrs, cfg);
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai }
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai Y.augment(MyClass, Y.Attribute);
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai});
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai```
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<h3>Registering Event Listeners</h3>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<p>Once we have an instance of the custom class, we can use the `on` and `after` methods provided by Attribute, to listen for changes in the value of each of the attributes:</p>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai```
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desaivar o1 = new MyClass();
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai...
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai// Event Listners
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desaio1.after("fooChange", function(e) {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai displayEvent(e, "After fooChange");
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai currentValSpan.set("innerHTML", Y.Escape.html(e.newVal+""));
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai});
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desaio1.after("barChange", function(e) {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai displayEvent(e, "After barChange");
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai currentValSpan.set("innerHTML", Y.Escape.html(e.newVal+""));
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai});
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desaio1.on("foobarChange", function(e) {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai if (preventFoobarChk.get("checked")) {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai // Calling preventDefault, in an "on" listener
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai // will prevent the attribute change from occuring
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai // and the after listener being called.
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai e.preventDefault();
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai displayEvent(null, "On foobarChange (prevented)");
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai }
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai});
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desaio1.after("foobarChange", function(e) {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai // This foobar after listener will not get called,
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai // if we end up preventing default in the "on"
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai // listener above.
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai displayEvent(e, "After foobarChange");
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai currentValSpan.set("innerHTML", Y.Escape.html(e.newVal+""));
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai});
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai```
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<p>As seen in the above code, the event type for attribute change events is created by concatenating the attribute name with `"Change"` (e.g. `"fooChange"`), and this event type is used for both the `on` and `after` subscription methods. Whenever an attribute value is changed through Attribute's `set` method, both "on" and "after" subscribers are notified.</p>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<h3>On vs. After</h3>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<p><strong>on :</strong> Subscribers to the "on" moment, will be notified <em>before</em> any actual state change has occurred. This provides the opportunity to prevent the state change from occurring, using the `preventDefault` method of the event facade object passed to the subscriber. If you use `get` to retrieve the value of the attribute in an "on" subscriber, you will receive the current, unchanged value. However the event facade provides access to the value which the attribute is being set to, through it's `newVal` property.</p>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<p><strong>after :</strong> Subscribers to the "after" moment, will be notified <em>after</em> the attribute's state has been updated. This provides the opportunity to update state in other parts of your application, in response to a change in the attribute's state.</p>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<p>Based on the definition above, `after` listeners are not invoked if state change is prevented, for example, due to one of the `on` listeners calling `preventDefault` on the event object, as is done in the `on` listener for the `foobar` attribute:</p>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai```
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desaio1.on("foobarChange", function(event) {
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai // Calling preventDefault, in an "on" listener
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai // will prevent the attribute change from occurring
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai // and prevent the after listeners from being called
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai displayEvent(event, "on foobarChange (change prevented)");
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai event.preventDefault();
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai});
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai```
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<p>For primitive values (non-Object values), the `after` listeners will also not be invoked if there is no change in the actual value of the attribute. That is, if the new value of the attribute is the same as the current value (based on the identity operator, `===`), the `after` listeners will not be notified because there is no change in state. You can see this, by setting an attribute to the same value twice in a row.</p>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<h3>Event Facade</h3>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<p>The event object (an instance of <a href="{{apiDocs}}/EventFacade.html">EventFacade</a>) passed to attribute change event subscribers, has the following interesting properties and methods related to attribute management:</p>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<dl>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai <dt>newVal</dt>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai <dd>The value which the attribute will be set to (in the case of "on" subscribers), or has been set to (in the case of "after" subscribers</dd>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai <dt>prevVal</dt>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai <dd>The value which the attribute is currently set to (in the case of "on" subscribers), or was previously set to (in the case of "after" subscribers</dd>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai <dt>attrName</dt>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai <dd>The name of the attribute which is being set</dd>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai <dt>subAttrName</dt>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai <dd>Attribute also allows you to set nested properties of attributes which have values which are objects through the
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai `set` method (e.g. `o1.set("x.y.z")`). This property will contain the path to the property which was changed.</dd>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai <dt>preventDefault()<dt>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai <dd>This method can be called in an "on" subscriber to prevent the attribute's value from being updated (the default behavior). Calling this method in an "after" listener has no impact, since the default behavior has already been invoked.</dd>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai <dt>stopImmediatePropagation()</dt>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai <dd>This method can be called in "on" or "after" subscribers, and will prevent the rest of the subscriber stack from
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai being invoked, but will not prevent the attribute's value from being updated.</dd>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai</dl>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<p>The <a href="attribute-event-speeddate.html">"Attribute Event Based Speed Dating" example</a> provides a look at how you can leverage attribute change events in your applications, to decouple logic both within your class, and when interacting with other objects.</p>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai<h2>Complete Example Source</h2>
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai```
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai{{>attribute-event-source}}
e808b8824ca1091c8efb5669db9129e68e5e1c14Satyen Desai```