|
1 |
|
2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> |
|
3 <html> |
|
4 <head> |
|
5 <title>YUI Library Examples: Attribute: Attribute Event Based Speed Dating</title> |
|
6 <meta http-equiv="content-type" content="text/html; charset=utf-8"> |
|
7 <link rel="stylesheet" type="text/css" href="../../assets/yui.css" > |
|
8 |
|
9 <style> |
|
10 /*Supplemental CSS for the YUI distribution*/ |
|
11 #custom-doc { width: 95%; min-width: 950px; } |
|
12 #pagetitle {background-image: url(../../assets/bg_hd.gif);} |
|
13 /* #pagetitle h1 {background-image: url(../../assets/title_h_bg.gif);}*/ |
|
14 </style> |
|
15 |
|
16 <link rel="stylesheet" type="text/css" href="../../assets/dpSyntaxHighlighter.css"> |
|
17 <link type="text/css" rel="stylesheet" href="../../build/cssfonts/fonts-min.css" /> |
|
18 <script type="text/javascript" src="../../build/yui/yui-min.js"></script> |
|
19 <style type="text/css"> |
|
20 #speeddate h1 { |
|
21 font-size: 108%; |
|
22 color:#000; |
|
23 margin-bottom:2em; |
|
24 } |
|
25 |
|
26 #john { |
|
27 margin-bottom:10px; |
|
28 } |
|
29 |
|
30 .interests.disabled, .reconsider.disabled { |
|
31 color:#888; |
|
32 } |
|
33 |
|
34 #john .interest { |
|
35 margin-left:5px; |
|
36 } |
|
37 |
|
38 .sd-nametag { |
|
39 border:1px solid #000; |
|
40 text-align:center; |
|
41 width:25em; |
|
42 margin:20px; |
|
43 |
|
44 background-color:#00f; |
|
45 |
|
46 border-radius: 10px; |
|
47 -webkit-border-radius: 10px; |
|
48 -moz-border-radius: 10px; |
|
49 |
|
50 box-shadow: 3px 3px 3px #888; |
|
51 -moz-box-shadow: 3px 3px 3px #888; |
|
52 -webkit-box-shadow: 3px 3px 3px #888; |
|
53 } |
|
54 |
|
55 .sd-nametag .sd-hd, |
|
56 .sd-nametag .sd-ft { |
|
57 padding:5px; |
|
58 text-align:center; |
|
59 font-size:108%; |
|
60 font-weight:900; |
|
61 color:#fff; |
|
62 } |
|
63 |
|
64 .sd-nametag .sd-hd { |
|
65 border-top-right-radius: 10px; |
|
66 border-top-left-radius: 10px; |
|
67 -moz-border-radius-topright: 10px; |
|
68 -moz-border-radius-topleft: 10px; |
|
69 -webkit-border-top-right-radius: 10px; |
|
70 -webkit-border-top-left-radius: 10px; |
|
71 } |
|
72 |
|
73 .sd-nametag .sd-ft { |
|
74 border-bottom-right-radius: 10px; |
|
75 border-bottom-left-radius: 10px; |
|
76 -moz-border-radius-bottomright: 10px; |
|
77 -moz-border-radius-bottomleft: 10px; |
|
78 -webkit-border-bottom-right-radius: 10px; |
|
79 -webkit-border-bottom-left-radius: 10px; |
|
80 } |
|
81 |
|
82 .sd-nametag .sd-bd { |
|
83 background-color:#fff; |
|
84 padding:0.5em; |
|
85 } |
|
86 |
|
87 .sd-nametag .sd-bd .sd-name, |
|
88 .sd-nametag .sd-bd .sd-personality, |
|
89 .sd-nametag .sd-bd .sd-interests { |
|
90 font-size:108%; |
|
91 font-weight:900; |
|
92 font-family:monospace; |
|
93 text-decoration:underline; |
|
94 color:#00a; |
|
95 } |
|
96 </style> |
|
97 </head> |
|
98 <body id="yahoo-com" class=" yui-skin-sam"> |
|
99 <div id="custom-doc" class="yui-t2"> |
|
100 <div id="hd"> |
|
101 <div id="ygunav"> |
|
102 <p> |
|
103 <em> |
|
104 <a href="http://developer.yahoo.com/yui/3/">YUI 3.x Home</a> <i> - </i> |
|
105 </em> |
|
106 </p> |
|
107 <form action="http://search.yahoo.com/search" id="sitesearchform"> |
|
108 <input name="vs" type="hidden" value="developer.yahoo.com"> |
|
109 <input name="vs" type="hidden" value="yuiblog.com"> |
|
110 <div id="sitesearch"> |
|
111 <label for="searchinput">Site Search (YDN & YUIBlog): </label> |
|
112 <input type="text" id="searchinput" name="p"> |
|
113 <input type="submit" value="Search" id="searchsubmit" class="ygbt"> |
|
114 </div> |
|
115 </form> |
|
116 </div> |
|
117 <div id="ygma"><a href="../../"><img src="../../assets/logo.gif" border="0" width="200" height="93"></a></div> |
|
118 <div id="pagetitle"><h1>YUI Library Examples: Attribute: Attribute Event Based Speed Dating</h1></div> |
|
119 </div> |
|
120 <div id="bd"> |
|
121 |
|
122 |
|
123 <div id="yui-main"> |
|
124 <div class="yui-b"> |
|
125 <div class="yui-ge"> |
|
126 <div class="yui-u first example" id="main"> |
|
127 |
|
128 <h2>Attribute: Attribute Event Based Speed Dating</h2> |
|
129 |
|
130 <div id="example" class="promo"> |
|
131 <div class="example-intro"> |
|
132 <p>Attribute change events are one of the key benefits of using attributes to maintain state for your objects, instead of regular object properties.</p> |
|
133 |
|
134 <p>This example refactors the basic <a href="attribute-basic-speeddate.html">"Attribute Based Speed Dating" example</a> to shows how you can listen for attribute change events to tie together your object's internal logic (such as updating the visual presentation of the object), and also to communicate with other objects.</p> |
|
135 </div> |
|
136 |
|
137 <div class="module example-container "> |
|
138 <div class="hd exampleHd"> |
|
139 <p class="newWindowButton yui-skin-sam"> |
|
140 <a href="attribute-event-speeddate_clean.html" target="_blank">View example in new window.</a> |
|
141 </p> |
|
142 </div> <div id="example-canvas" class="bd"> |
|
143 |
|
144 |
|
145 <!--BEGIN SOURCE CODE FOR EXAMPLE =============================== --> |
|
146 |
|
147 <div id="speeddate"> |
|
148 |
|
149 <h1>Communicating With Attribute Events On Speed Dates</h1> |
|
150 |
|
151 <div id="john"> |
|
152 <button type="button" class="hi">Hi, I'm John</button> |
|
153 |
|
154 <span class="interests disabled"> |
|
155 I enjoy: |
|
156 <label><input type="checkbox" class="interest" value="Sunsets" disabled="disabled"> Sunsets</label> |
|
157 <label><input type="checkbox" class="interest" value="Reading Specifications" disabled="disabled"> Reading Specifications</label> |
|
158 <label><input type="checkbox" class="interest" value="Saving Whales" disabled="disabled"> Saving Whales</label> |
|
159 <label><input type="checkbox" class="interest" value="Knitting" disabled="disabled"> Knitting</label> |
|
160 </span> |
|
161 <div class="shirt"></div> |
|
162 </div> |
|
163 |
|
164 <div id="jane"> |
|
165 <button type="button" class="hi" disabled="disabled">Hey, I'm Jane</button> |
|
166 <button type="button" class="movingOn" disabled="disabled">I'm Moving On...</button> <span class="reconsider disabled">(unless he likes whales, and avoids knitting <em class="message"></em>)</span> |
|
167 <div class="shirt"></div> |
|
168 </div> |
|
169 </div> |
|
170 |
|
171 <script type="text/javascript"> |
|
172 |
|
173 // Get a new instance of YUI and |
|
174 // load it with the required set of modules |
|
175 |
|
176 YUI({base:"../../build/", timeout: 10000}).use("collection", "event-delegate", "node", "attribute", "substitute", function(Y) { |
|
177 |
|
178 // Setup custom class which we want to add managed attribute support to |
|
179 |
|
180 function SpeedDater(cfg) { |
|
181 // When constructed, setup the initial attributes for the instance, by calling the addAttrs method. |
|
182 var attrs = { |
|
183 name : { |
|
184 writeOnce:true |
|
185 }, |
|
186 |
|
187 personality : { |
|
188 value:50 |
|
189 }, |
|
190 |
|
191 available : { |
|
192 value:true |
|
193 }, |
|
194 |
|
195 interests : { |
|
196 value : [] |
|
197 } |
|
198 }; |
|
199 |
|
200 this.addAttrs(attrs, cfg); |
|
201 } |
|
202 |
|
203 // The HTML template representing the SpeedDater name tag. |
|
204 SpeedDater.NAMETAG = '<div class="sd-nametag"> \ |
|
205 <div class="sd-hd">Hello!</div> \ |
|
206 <div class="sd-bd"> \ |
|
207 <p>I\'m <span class="sd-name">{name}</span> and my PersonalityQuotientIndex is <span class="sd-personality">{personality}</span></p> \ |
|
208 <p>I enjoy <span class="sd-interests">{interests}</span>.</p> \ |
|
209 </div> \ |
|
210 <div class="sd-ft sd-availability">{available}</div> \ |
|
211 </div>'; |
|
212 |
|
213 // Method used to render the visual representation of a SpeedDater object's state (in this case as a name tag) |
|
214 SpeedDater.prototype.applyNameTag = function(where) { |
|
215 |
|
216 var tokens = { |
|
217 name: this.get("name"), |
|
218 available: (this.get("available")) ? "" : "Sorry, moving on", |
|
219 personality: this.get("personality"), |
|
220 interests: (this.get("interests").length == 0) ? "absolutely nothing" : this.get("interests").join(", ") |
|
221 }; |
|
222 |
|
223 this.nameTag = Y.Node.create(Y.substitute(SpeedDater.NAMETAG, tokens)); |
|
224 Y.one(where).appendChild(this.nameTag); |
|
225 |
|
226 this.listenForChanges(); |
|
227 }; |
|
228 |
|
229 // Method used to attach attribute change event listeners, so that the SpeedDater instance |
|
230 // will react to changes in attribute state, and update what's rendered on the page |
|
231 SpeedDater.prototype.listenForChanges = function() { |
|
232 |
|
233 // Sync up the UI for "available", after the value of the "available" attribute has changed: |
|
234 this.after("availableChange", function(e) { |
|
235 var taken = (e.newVal) ? "" : "Oh, is that the time?"; |
|
236 this.nameTag.query(".sd-availability").set("innerHTML", taken); |
|
237 }); |
|
238 |
|
239 // Sync up the UI for "name", after the value of the "name" attribute has changed: |
|
240 this.after("nameChange", function(e) { |
|
241 var name = e.newVal; |
|
242 this.nameTag.query(".sd-name").set("innerHTML", name); |
|
243 }); |
|
244 |
|
245 // Sync up the UI for "personality", after the value of the "personality" attribute has changed: |
|
246 this.after("personalityChange", function(e) { |
|
247 var personality = e.newVal; |
|
248 |
|
249 var personalityEl = this.nameTag.query(".sd-personality"); |
|
250 personalityEl.set("innerHTML", personality); |
|
251 |
|
252 if (personality > 90) { |
|
253 personalityEl.addClass("sd-max"); |
|
254 } |
|
255 }); |
|
256 |
|
257 // Sync up the UI for "interests", after the value of the "interests" attribute has changed: |
|
258 this.after("interestsChange", function(e) { |
|
259 var interests = (e.newVal.length == 0) ? "absolutely nothing" : this.get("interests").join(", "); |
|
260 this.nameTag.query(".sd-interests").set("innerHTML", interests); |
|
261 }); |
|
262 }; |
|
263 |
|
264 // Augment custom class with Attribute |
|
265 Y.augment(SpeedDater, Y.Attribute); |
|
266 |
|
267 var john, jane; |
|
268 |
|
269 Y.on("click", function() { |
|
270 |
|
271 if (!john) { |
|
272 |
|
273 john = new SpeedDater({ |
|
274 name: "John", |
|
275 personality: 78 |
|
276 }); |
|
277 john.applyNameTag("#john .shirt"); |
|
278 |
|
279 Y.one("#jane .hi").set("disabled", false); |
|
280 } |
|
281 |
|
282 }, "#john .hi"); |
|
283 |
|
284 Y.on("click", function() { |
|
285 |
|
286 if (!jane) { |
|
287 |
|
288 jane = new SpeedDater({ |
|
289 name: "Jane", |
|
290 personality: 82, |
|
291 interests: ["Popcorn", "Saving Whales"] |
|
292 }); |
|
293 jane.applyNameTag("#jane .shirt"); |
|
294 |
|
295 // Update Jane's interests state, after John's interests state changes... |
|
296 john.after("interestsChange", function(e) { |
|
297 |
|
298 var janesInterests = jane.get("interests"), |
|
299 johnsInterests = e.newVal, |
|
300 |
|
301 readingSpecs = "Reading Specifications"; |
|
302 |
|
303 // If it turns out that John enjoys reading specs, then Jane can admit it too... |
|
304 if (Y.Array.indexOf(johnsInterests, readingSpecs) !== -1) { |
|
305 if(Y.Array.indexOf(janesInterests, readingSpecs) == -1) { |
|
306 janesInterests.push(readingSpecs); |
|
307 } |
|
308 } else { |
|
309 janesInterests = Y.Array.reject(janesInterests, function(item){return (item == readingSpecs);}); |
|
310 } |
|
311 |
|
312 jane.set("interests", janesInterests); |
|
313 jane.set("available", true); |
|
314 |
|
315 setMessage(""); |
|
316 }); |
|
317 |
|
318 // We can also listen before an attribute changes its value, and decide if we want to |
|
319 // allow the state change to occur or not. Invoking e.preventDefault() stops the state from |
|
320 // being updated. |
|
321 |
|
322 // In this case, Jane can change her mind about making herself unavailable, if John likes |
|
323 // saving whales, as long as he doesn't dig knitting too. |
|
324 |
|
325 jane.on("availableChange", function(e) { |
|
326 var johnsInterests = john.get("interests"); |
|
327 var janeAvailable = e.newVal; |
|
328 if (janeAvailable === false && Y.Array.indexOf(johnsInterests, "Saving Whales") !== -1 && Y.Array.indexOf(johnsInterests, "Knitting") == -1 ) { |
|
329 // Reconsider.. |
|
330 e.preventDefault(); |
|
331 |
|
332 setMessage("... which he does"); |
|
333 }; |
|
334 }); |
|
335 |
|
336 enableExampleUI(); |
|
337 } |
|
338 |
|
339 }, "#jane .hi"); |
|
340 |
|
341 Y.on("click", function() { |
|
342 jane.set("available", false); |
|
343 }, "#jane .movingOn"); |
|
344 |
|
345 // A delegate DOM event listener which will update John's interests, based on the checkbox state, whenever |
|
346 // a checkbox is clicked. |
|
347 Y.on("delegate", function() { |
|
348 var interests = []; |
|
349 |
|
350 Y.Node.all("#john input[type=checkbox].interest").each(function(checkbox) { |
|
351 if (checkbox.get("checked")) { |
|
352 interests.push(checkbox.get("value")); |
|
353 } |
|
354 }); |
|
355 john.set("interests", interests); |
|
356 |
|
357 }, "#john", "click", "input[type=checkbox].interest"); |
|
358 |
|
359 |
|
360 // Example helpers... |
|
361 function enableExampleUI() { |
|
362 Y.all("#jane button").set("disabled", false); |
|
363 Y.all("#john button").set("disabled", false); |
|
364 Y.all("#john input").set("disabled", false); |
|
365 Y.one("#john .interests").removeClass("disabled"); |
|
366 Y.one("#jane .reconsider").removeClass("disabled"); |
|
367 } |
|
368 |
|
369 function setMessage(msg) { |
|
370 Y.one("#jane .message").set("innerHTML", msg); |
|
371 } |
|
372 |
|
373 }); |
|
374 </script> |
|
375 |
|
376 <!--END SOURCE CODE FOR EXAMPLE =============================== --> |
|
377 |
|
378 |
|
379 </div> |
|
380 </div> |
|
381 </div> |
|
382 |
|
383 <h3>Listening For Attribute Change Events</h3> |
|
384 |
|
385 <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, |
|
386 using the <code>SpeedDater</code> class, introduced in the <a href="attribute-basic-speeddate.html">"Attribute Based Speed Dating" example</a>.</p> |
|
387 |
|
388 <p>We'll create two SpeedDater instances, <code>jane</code> and <code>john</code>, and use the attribute events they generate both internally (within the class code), to wire up UI refreshes, |
|
389 and externally, to have <code>jane</code> react to changes in the <code>john</code>'s state.</p> |
|
390 |
|
391 <h4>Setting Up The SpeedDater Class With Attribute</h4> |
|
392 |
|
393 <p>We start by setting up the same basic class we created for the <a href="attribute-basic-speeddate.html">"Attribute Based Speed Dating" example</a>, with an additional attribute, <code>interests</code>, using the code below:</p> |
|
394 |
|
395 <div id="syntax1" class="yui-syntax-highlight"><div class="numbers"><pre class="javascript" style="font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="co1">// Setup custom class which we want to add managed attribute support to</span></div></li><li class="li1"><div class="de1"><span class="kw2">function</span> SpeedDater<span class="br0">(</span>cfg<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="co1">// When constructed, setup the initial attributes for the instance, </span></div></li><li class="li1"><div class="de1"> <span class="co1">// by calling the addAttrs method.</span></div></li><li class="li2"><div class="de2"> <span class="kw2">var</span> attrs <span class="sy0">=</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw3">name</span> <span class="sy0">:</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> writeOnce<span class="sy0">:</span><span class="kw2">true</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li2"><div class="de2"> personality <span class="sy0">:</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> value<span class="sy0">:</span><span class="nu0">50</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> available <span class="sy0">:</span> <span class="br0">{</span></div></li><li class="li2"><div class="de2"> value<span class="sy0">:</span><span class="kw2">true</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span><span class="sy0">,</span> </div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> interests <span class="sy0">:</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> value <span class="sy0">:</span> <span class="br0">[</span><span class="br0">]</span></div></li><li class="li2"><div class="de2"> <span class="br0">}</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>.<span class="me1">addAttrs</span><span class="br0">(</span>attrs<span class="sy0">,</span> cfg<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span></div></li><li class="li2"><div class="de2"> </div></li><li class="li1"><div class="de1"><span class="co1">// Augment custom class with Attribute</span></div></li><li class="li1"><div class="de1">Y.<span class="me1">augment</span><span class="br0">(</span>SpeedDater<span class="sy0">,</span> Y.<span class="me1">Attribute</span><span class="br0">)</span><span class="sy0">;</span></div></li></ol></pre></div><div class="nonumbers"><pre class="javascript" style="font-family:monospace;"><span class="co1">// Setup custom class which we want to add managed attribute support to</span> |
|
396 <span class="kw2">function</span> SpeedDater<span class="br0">(</span>cfg<span class="br0">)</span> <span class="br0">{</span> |
|
397 <span class="co1">// When constructed, setup the initial attributes for the instance, </span> |
|
398 <span class="co1">// by calling the addAttrs method.</span> |
|
399 <span class="kw2">var</span> attrs <span class="sy0">=</span> <span class="br0">{</span> |
|
400 <span class="kw3">name</span> <span class="sy0">:</span> <span class="br0">{</span> |
|
401 writeOnce<span class="sy0">:</span><span class="kw2">true</span> |
|
402 <span class="br0">}</span><span class="sy0">,</span> |
|
403 |
|
404 personality <span class="sy0">:</span> <span class="br0">{</span> |
|
405 value<span class="sy0">:</span><span class="nu0">50</span> |
|
406 <span class="br0">}</span><span class="sy0">,</span> |
|
407 |
|
408 available <span class="sy0">:</span> <span class="br0">{</span> |
|
409 value<span class="sy0">:</span><span class="kw2">true</span> |
|
410 <span class="br0">}</span><span class="sy0">,</span> |
|
411 |
|
412 interests <span class="sy0">:</span> <span class="br0">{</span> |
|
413 value <span class="sy0">:</span> <span class="br0">[</span><span class="br0">]</span> |
|
414 <span class="br0">}</span> |
|
415 <span class="br0">}</span><span class="sy0">;</span> |
|
416 |
|
417 <span class="kw1">this</span>.<span class="me1">addAttrs</span><span class="br0">(</span>attrs<span class="sy0">,</span> cfg<span class="br0">)</span><span class="sy0">;</span> |
|
418 <span class="br0">}</span> |
|
419 |
|
420 <span class="co1">// Augment custom class with Attribute</span> |
|
421 Y.<span class="me1">augment</span><span class="br0">(</span>SpeedDater<span class="sy0">,</span> Y.<span class="me1">Attribute</span><span class="br0">)</span><span class="sy0">;</span></pre></div><textarea id="syntax1-plain">// Setup custom class which we want to add managed attribute support to |
|
422 function SpeedDater(cfg) { |
|
423 // When constructed, setup the initial attributes for the instance, |
|
424 // by calling the addAttrs method. |
|
425 var attrs = { |
|
426 name : { |
|
427 writeOnce:true |
|
428 }, |
|
429 |
|
430 personality : { |
|
431 value:50 |
|
432 }, |
|
433 |
|
434 available : { |
|
435 value:true |
|
436 }, |
|
437 |
|
438 interests : { |
|
439 value : [] |
|
440 } |
|
441 }; |
|
442 |
|
443 this.addAttrs(attrs, cfg); |
|
444 } |
|
445 |
|
446 // Augment custom class with Attribute |
|
447 Y.augment(SpeedDater, Y.Attribute);</textarea></div> |
|
448 <p>We then create two instances of SpeedDaters, <code>jane</code> and <code>john</code>:</p> |
|
449 |
|
450 <div id="syntax2" class="yui-syntax-highlight"><div class="numbers"><pre class="javascript" style="font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="co1">// Create a john instance...</span></div></li><li class="li1"><div class="de1">john <span class="sy0">=</span> <span class="kw2">new</span> SpeedDater<span class="br0">(</span><span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw3">name</span><span class="sy0">:</span> <span class="st0">"John"</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> personality<span class="sy0">:</span> <span class="nu0">78</span></div></li><li class="li2"><div class="de2"><span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="co1">// ... and render to the page</span></div></li><li class="li1"><div class="de1">john.<span class="me1">applyNameTag</span><span class="br0">(</span><span class="st0">"#john .shirt"</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="co1">// Create a jane instance...</span></div></li><li class="li2"><div class="de2">jane <span class="sy0">=</span> <span class="kw2">new</span> SpeedDater<span class="br0">(</span><span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw3">name</span><span class="sy0">:</span> <span class="st0">"Jane"</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> personality<span class="sy0">:</span> <span class="nu0">82</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> interests<span class="sy0">:</span> <span class="br0">[</span><span class="st0">"Popcorn"</span><span class="sy0">,</span> <span class="st0">"Saving Whales"</span><span class="br0">]</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2">jane.<span class="me1">applyNameTag</span><span class="br0">(</span><span class="st0">"#jane .shirt"</span><span class="br0">)</span><span class="sy0">;</span></div></li></ol></pre></div><div class="nonumbers"><pre class="javascript" style="font-family:monospace;"><span class="co1">// Create a john instance...</span> |
|
451 john <span class="sy0">=</span> <span class="kw2">new</span> SpeedDater<span class="br0">(</span><span class="br0">{</span> |
|
452 <span class="kw3">name</span><span class="sy0">:</span> <span class="st0">"John"</span><span class="sy0">,</span> |
|
453 personality<span class="sy0">:</span> <span class="nu0">78</span> |
|
454 <span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span> |
|
455 <span class="co1">// ... and render to the page</span> |
|
456 john.<span class="me1">applyNameTag</span><span class="br0">(</span><span class="st0">"#john .shirt"</span><span class="br0">)</span><span class="sy0">;</span> |
|
457 |
|
458 <span class="co1">// Create a jane instance...</span> |
|
459 jane <span class="sy0">=</span> <span class="kw2">new</span> SpeedDater<span class="br0">(</span><span class="br0">{</span> |
|
460 <span class="kw3">name</span><span class="sy0">:</span> <span class="st0">"Jane"</span><span class="sy0">,</span> |
|
461 personality<span class="sy0">:</span> <span class="nu0">82</span><span class="sy0">,</span> |
|
462 interests<span class="sy0">:</span> <span class="br0">[</span><span class="st0">"Popcorn"</span><span class="sy0">,</span> <span class="st0">"Saving Whales"</span><span class="br0">]</span> |
|
463 <span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span> |
|
464 jane.<span class="me1">applyNameTag</span><span class="br0">(</span><span class="st0">"#jane .shirt"</span><span class="br0">)</span><span class="sy0">;</span></pre></div><textarea id="syntax2-plain">// Create a john instance... |
|
465 john = new SpeedDater({ |
|
466 name: "John", |
|
467 personality: 78 |
|
468 }); |
|
469 // ... and render to the page |
|
470 john.applyNameTag("#john .shirt"); |
|
471 |
|
472 // Create a jane instance... |
|
473 jane = new SpeedDater({ |
|
474 name: "Jane", |
|
475 personality: 82, |
|
476 interests: ["Popcorn", "Saving Whales"] |
|
477 }); |
|
478 jane.applyNameTag("#jane .shirt");</textarea></div> |
|
479 <h4>Registering Event Listeners</h4> |
|
480 |
|
481 <p>For this event based example, we no longer have an <code>updateNameTag()</code> method which the user is responsible for calling when they want to refresh the name tag rendered on the page, as we did in the basic example. |
|
482 Instead the <code>SpeedDater</code> class sets up some internal attribute change event listeners in its <code>listenForChanges()</code> method, which will refresh the UI for a particular attribute, each time its value is modified:</p> |
|
483 |
|
484 <div id="syntax3" class="yui-syntax-highlight"><div class="numbers"><pre class="javascript" style="font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="co1">// Method used to attach attribute change event listeners, so that </span></div></li><li class="li1"><div class="de1"><span class="co1">// the SpeedDater instance will react to changes in attribute state, </span></div></li><li class="li1"><div class="de1"><span class="co1">// and update what's rendered on the page</span></div></li><li class="li1"><div class="de1">SpeedDater.<span class="me1">prototype</span>.<span class="me1">listenForChanges</span> <span class="sy0">=</span> <span class="kw2">function</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span></div></li><li class="li2"><div class="de2"> </div></li><li class="li1"><div class="de1"> <span class="co1">// Sync up the UI for "available", after the value of the "available" </span></div></li><li class="li1"><div class="de1"> <span class="co1">// attribute has changed:</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>.<span class="me1">after</span><span class="br0">(</span><span class="st0">"availableChange"</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw2">var</span> taken <span class="sy0">=</span> <span class="br0">(</span>e.<span class="me1">newVal</span><span class="br0">)</span> <span class="sy0">?</span> <span class="st0">""</span> <span class="sy0">:</span> <span class="st0">"Oh, is that the time?"</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2"> <span class="kw1">this</span>.<span class="me1">nameTag</span>.<span class="me1">query</span><span class="br0">(</span><span class="st0">".sd-availability"</span><span class="br0">)</span>.<span class="me1">set</span><span class="br0">(</span><span class="st0">"innerHTML"</span><span class="sy0">,</span> taken<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="co1">// Sync up the UI for "name", after the value of the "name" </span></div></li><li class="li1"><div class="de1"> <span class="co1">// attribute has changed:</span></div></li><li class="li2"><div class="de2"> <span class="kw1">this</span>.<span class="me1">after</span><span class="br0">(</span><span class="st0">"nameChange"</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw2">var</span> <span class="kw3">name</span> <span class="sy0">=</span> e.<span class="me1">newVal</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>.<span class="me1">nameTag</span>.<span class="me1">query</span><span class="br0">(</span><span class="st0">".sd-name"</span><span class="br0">)</span>.<span class="me1">set</span><span class="br0">(</span><span class="st0">"innerHTML"</span><span class="sy0">,</span> <span class="kw3">name</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li2"><div class="de2"> <span class="co1">// Sync up the UI for "personality", after the value of the "personality" </span></div></li><li class="li1"><div class="de1"> <span class="co1">// attribute has changed:</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>.<span class="me1">after</span><span class="br0">(</span><span class="st0">"personalityChange"</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw2">var</span> personality <span class="sy0">=</span> e.<span class="me1">newVal</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li2"><div class="de2"> <span class="kw2">var</span> personalityEl <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">nameTag</span>.<span class="me1">query</span><span class="br0">(</span><span class="st0">".sd-personality"</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> personalityEl.<span class="me1">set</span><span class="br0">(</span><span class="st0">"innerHTML"</span><span class="sy0">,</span> personality<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">(</span>personality <span class="sy0">></span> <span class="nu0">90</span><span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> personalityEl.<span class="me1">addClass</span><span class="br0">(</span><span class="st0">"sd-max"</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2"> <span class="br0">}</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="co1">// Sync up the UI for "interests", after the value of the "interests" </span></div></li><li class="li1"><div class="de1"> <span class="co1">// attribute has changed:</span></div></li><li class="li2"><div class="de2"> <span class="kw1">this</span>.<span class="me1">after</span><span class="br0">(</span><span class="st0">"interestsChange"</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw2">var</span> interests <span class="sy0">=</span> <span class="br0">(</span>e.<span class="me1">newVal</span>.<span class="me1">length</span> <span class="sy0">==</span> <span class="nu0">0</span><span class="br0">)</span> <span class="sy0">?</span> </div></li><li class="li1"><div class="de1"> <span class="st0">"absolutely nothing"</span> <span class="sy0">:</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"interests"</span><span class="br0">)</span>.<span class="me1">join</span><span class="br0">(</span><span class="st0">", "</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>.<span class="me1">nameTag</span>.<span class="me1">query</span><span class="br0">(</span><span class="st0">".sd-interests"</span><span class="br0">)</span>.<span class="me1">set</span><span class="br0">(</span><span class="st0">"innerHTML"</span><span class="sy0">,</span> interests<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2"><span class="br0">}</span><span class="sy0">;</span></div></li></ol></pre></div><div class="nonumbers"><pre class="javascript" style="font-family:monospace;"><span class="co1">// Method used to attach attribute change event listeners, so that </span> |
|
485 <span class="co1">// the SpeedDater instance will react to changes in attribute state, </span> |
|
486 <span class="co1">// and update what's rendered on the page</span> |
|
487 SpeedDater.<span class="me1">prototype</span>.<span class="me1">listenForChanges</span> <span class="sy0">=</span> <span class="kw2">function</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> |
|
488 |
|
489 <span class="co1">// Sync up the UI for "available", after the value of the "available" </span> |
|
490 <span class="co1">// attribute has changed:</span> |
|
491 <span class="kw1">this</span>.<span class="me1">after</span><span class="br0">(</span><span class="st0">"availableChange"</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span> |
|
492 <span class="kw2">var</span> taken <span class="sy0">=</span> <span class="br0">(</span>e.<span class="me1">newVal</span><span class="br0">)</span> <span class="sy0">?</span> <span class="st0">""</span> <span class="sy0">:</span> <span class="st0">"Oh, is that the time?"</span><span class="sy0">;</span> |
|
493 <span class="kw1">this</span>.<span class="me1">nameTag</span>.<span class="me1">query</span><span class="br0">(</span><span class="st0">".sd-availability"</span><span class="br0">)</span>.<span class="me1">set</span><span class="br0">(</span><span class="st0">"innerHTML"</span><span class="sy0">,</span> taken<span class="br0">)</span><span class="sy0">;</span> |
|
494 <span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span> |
|
495 |
|
496 <span class="co1">// Sync up the UI for "name", after the value of the "name" </span> |
|
497 <span class="co1">// attribute has changed:</span> |
|
498 <span class="kw1">this</span>.<span class="me1">after</span><span class="br0">(</span><span class="st0">"nameChange"</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span> |
|
499 <span class="kw2">var</span> <span class="kw3">name</span> <span class="sy0">=</span> e.<span class="me1">newVal</span><span class="sy0">;</span> |
|
500 <span class="kw1">this</span>.<span class="me1">nameTag</span>.<span class="me1">query</span><span class="br0">(</span><span class="st0">".sd-name"</span><span class="br0">)</span>.<span class="me1">set</span><span class="br0">(</span><span class="st0">"innerHTML"</span><span class="sy0">,</span> <span class="kw3">name</span><span class="br0">)</span><span class="sy0">;</span> |
|
501 <span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span> |
|
502 |
|
503 <span class="co1">// Sync up the UI for "personality", after the value of the "personality" </span> |
|
504 <span class="co1">// attribute has changed:</span> |
|
505 <span class="kw1">this</span>.<span class="me1">after</span><span class="br0">(</span><span class="st0">"personalityChange"</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span> |
|
506 <span class="kw2">var</span> personality <span class="sy0">=</span> e.<span class="me1">newVal</span><span class="sy0">;</span> |
|
507 |
|
508 <span class="kw2">var</span> personalityEl <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">nameTag</span>.<span class="me1">query</span><span class="br0">(</span><span class="st0">".sd-personality"</span><span class="br0">)</span><span class="sy0">;</span> |
|
509 personalityEl.<span class="me1">set</span><span class="br0">(</span><span class="st0">"innerHTML"</span><span class="sy0">,</span> personality<span class="br0">)</span><span class="sy0">;</span> |
|
510 |
|
511 <span class="kw1">if</span> <span class="br0">(</span>personality <span class="sy0">></span> <span class="nu0">90</span><span class="br0">)</span> <span class="br0">{</span> |
|
512 personalityEl.<span class="me1">addClass</span><span class="br0">(</span><span class="st0">"sd-max"</span><span class="br0">)</span><span class="sy0">;</span> |
|
513 <span class="br0">}</span> |
|
514 <span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span> |
|
515 |
|
516 <span class="co1">// Sync up the UI for "interests", after the value of the "interests" </span> |
|
517 <span class="co1">// attribute has changed:</span> |
|
518 <span class="kw1">this</span>.<span class="me1">after</span><span class="br0">(</span><span class="st0">"interestsChange"</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span> |
|
519 <span class="kw2">var</span> interests <span class="sy0">=</span> <span class="br0">(</span>e.<span class="me1">newVal</span>.<span class="me1">length</span> <span class="sy0">==</span> <span class="nu0">0</span><span class="br0">)</span> <span class="sy0">?</span> |
|
520 <span class="st0">"absolutely nothing"</span> <span class="sy0">:</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"interests"</span><span class="br0">)</span>.<span class="me1">join</span><span class="br0">(</span><span class="st0">", "</span><span class="br0">)</span><span class="sy0">;</span> |
|
521 <span class="kw1">this</span>.<span class="me1">nameTag</span>.<span class="me1">query</span><span class="br0">(</span><span class="st0">".sd-interests"</span><span class="br0">)</span>.<span class="me1">set</span><span class="br0">(</span><span class="st0">"innerHTML"</span><span class="sy0">,</span> interests<span class="br0">)</span><span class="sy0">;</span> |
|
522 <span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span> |
|
523 <span class="br0">}</span><span class="sy0">;</span></pre></div><textarea id="syntax3-plain">// Method used to attach attribute change event listeners, so that |
|
524 // the SpeedDater instance will react to changes in attribute state, |
|
525 // and update what's rendered on the page |
|
526 SpeedDater.prototype.listenForChanges = function() { |
|
527 |
|
528 // Sync up the UI for "available", after the value of the "available" |
|
529 // attribute has changed: |
|
530 this.after("availableChange", function(e) { |
|
531 var taken = (e.newVal) ? "" : "Oh, is that the time?"; |
|
532 this.nameTag.query(".sd-availability").set("innerHTML", taken); |
|
533 }); |
|
534 |
|
535 // Sync up the UI for "name", after the value of the "name" |
|
536 // attribute has changed: |
|
537 this.after("nameChange", function(e) { |
|
538 var name = e.newVal; |
|
539 this.nameTag.query(".sd-name").set("innerHTML", name); |
|
540 }); |
|
541 |
|
542 // Sync up the UI for "personality", after the value of the "personality" |
|
543 // attribute has changed: |
|
544 this.after("personalityChange", function(e) { |
|
545 var personality = e.newVal; |
|
546 |
|
547 var personalityEl = this.nameTag.query(".sd-personality"); |
|
548 personalityEl.set("innerHTML", personality); |
|
549 |
|
550 if (personality > 90) { |
|
551 personalityEl.addClass("sd-max"); |
|
552 } |
|
553 }); |
|
554 |
|
555 // Sync up the UI for "interests", after the value of the "interests" |
|
556 // attribute has changed: |
|
557 this.after("interestsChange", function(e) { |
|
558 var interests = (e.newVal.length == 0) ? |
|
559 "absolutely nothing" : this.get("interests").join(", "); |
|
560 this.nameTag.query(".sd-interests").set("innerHTML", interests); |
|
561 }); |
|
562 };</textarea></div> |
|
563 <p> |
|
564 As seen in the above code, the event type for attribute change events is created by concatenating the attribute name with <code>"Change"</code> (e.g. <code>"availableChange"</code>). Whenever an attribute value is changed through Attribute's <code>set()</code> method, both <em>"on"</em> and <em>"after"</em> subscribers are notified. |
|
565 </p> |
|
566 <p> |
|
567 In the code snippet above, all the subscribers are listening for the <em>"after"</em> moment using the <code>after()</code> subscription method, since they're only interested in being notified after the value has actually changed. |
|
568 However, as we'll see below, the example also shows you how to use an <em>"on"</em> listener, to prevent the attribute state change from occuring under certain conditions. |
|
569 </p> |
|
570 |
|
571 <h4>On vs. After</h4> |
|
572 |
|
573 <p>A single attribute change event has two moments which can be subscribed to, depending on what the subscriber wants to do when notified.</p> |
|
574 |
|
575 <p><strong>on :</strong> Subscribers to the <em>"on"</em> moment, will be notified <em>before</em> any actual state change has occurred. This provides the opportunity to prevent the state change from occurring, |
|
576 using the <code>preventDefault()</code> method of the event facade object passed to the subscriber. If you use <code>get()</code> to retrieve the value of the attribute in an <em>"on"</em> subscriber, you will receive the current, unchanged value. |
|
577 However the event facade provides access to the value which the attribute is being set to, through it's <code>newVal</code> property.</p> |
|
578 |
|
579 <p><strong>after :</strong> Subscribers to the <em>"after"</em> moment, will be notified <em>after</em> the attribute's state has been updated. |
|
580 This provides the opportunity to update state in other parts of your application, in response to a change in the attribute's state.</p> |
|
581 |
|
582 <p>Based on the definition above, <code>after</code> listeners are not invoked if state change is prevented; for example, due to one of the <em>"on"</em> listeners calling <code>preventDefault()</code> on the event object passed to the subscriber.</p> |
|
583 |
|
584 <h4>Having Jane React To John</h4> |
|
585 |
|
586 <p>Aside from the internal listeners set up by the class, in this example <code>jane</code> also sets up two more subscribers. The first is a subscriber, which allows <code>jane</code> to "reconsider" changing the state of her <code>available</code> attribute, |
|
587 under certain conditions. Since she may want to prevent the <code>available</code> attribute from being modified in this case, we use Attribute's <code>on()</code> method to listen for the <em>"on"</em> moment, so that the default behavior can be prevented:</p> |
|
588 |
|
589 <div id="syntax4" class="yui-syntax-highlight"><div class="numbers"><pre class="javascript" style="font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="co1">// We can also listen before an attribute changes its value, and </span></div></li><li class="li1"><div class="de1"><span class="co1">// decide if we want to allow the state change to occur or not. </span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="co1">// Invoking e.preventDefault() stops the state from being updated. </span></div></li><li class="li2"><div class="de2"> </div></li><li class="li1"><div class="de1"><span class="co1">// In this case, Jane can change her mind about making herself </span></div></li><li class="li1"><div class="de1"><span class="co1">// unavailable, if John likes saving whales, as long as he doesn't </span></div></li><li class="li1"><div class="de1"><span class="co1">// dig knitting too.</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li2"><div class="de2">jane.<span class="me1">on</span><span class="br0">(</span><span class="st0">"availableChange"</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw2">var</span> johnsInterests <span class="sy0">=</span> john.<span class="me1">get</span><span class="br0">(</span><span class="st0">"interests"</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw2">var</span> janeAvailable <span class="sy0">=</span> e.<span class="me1">newVal</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">(</span>janeAvailable <span class="sy0">===</span> <span class="kw2">false</span> <span class="sy0">&&</span> Y.<span class="me1">Array</span>.<span class="me1">indexOf</span><span class="br0">(</span>johnsInterests<span class="sy0">,</span> <span class="st0">"Saving Whales"</span><span class="br0">)</span> <span class="sy0">!==</span> <span class="sy0">-</span><span class="nu0">1</span> </div></li><li class="li2"><div class="de2"> <span class="sy0">&&</span> Y.<span class="me1">Array</span>.<span class="me1">indexOf</span><span class="br0">(</span>johnsInterests<span class="sy0">,</span> <span class="st0">"Knitting"</span><span class="br0">)</span> <span class="sy0">==</span> <span class="sy0">-</span><span class="nu0">1</span> <span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="co1">// Reconsider..</span></div></li><li class="li1"><div class="de1"> e.<span class="me1">preventDefault</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span></div></li></ol></pre></div><div class="nonumbers"><pre class="javascript" style="font-family:monospace;"><span class="co1">// We can also listen before an attribute changes its value, and </span> |
|
590 <span class="co1">// decide if we want to allow the state change to occur or not. </span> |
|
591 |
|
592 <span class="co1">// Invoking e.preventDefault() stops the state from being updated. </span> |
|
593 |
|
594 <span class="co1">// In this case, Jane can change her mind about making herself </span> |
|
595 <span class="co1">// unavailable, if John likes saving whales, as long as he doesn't </span> |
|
596 <span class="co1">// dig knitting too.</span> |
|
597 |
|
598 jane.<span class="me1">on</span><span class="br0">(</span><span class="st0">"availableChange"</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span> |
|
599 <span class="kw2">var</span> johnsInterests <span class="sy0">=</span> john.<span class="me1">get</span><span class="br0">(</span><span class="st0">"interests"</span><span class="br0">)</span><span class="sy0">;</span> |
|
600 <span class="kw2">var</span> janeAvailable <span class="sy0">=</span> e.<span class="me1">newVal</span><span class="sy0">;</span> |
|
601 |
|
602 <span class="kw1">if</span> <span class="br0">(</span>janeAvailable <span class="sy0">===</span> <span class="kw2">false</span> <span class="sy0">&&</span> Y.<span class="me1">Array</span>.<span class="me1">indexOf</span><span class="br0">(</span>johnsInterests<span class="sy0">,</span> <span class="st0">"Saving Whales"</span><span class="br0">)</span> <span class="sy0">!==</span> <span class="sy0">-</span><span class="nu0">1</span> |
|
603 <span class="sy0">&&</span> Y.<span class="me1">Array</span>.<span class="me1">indexOf</span><span class="br0">(</span>johnsInterests<span class="sy0">,</span> <span class="st0">"Knitting"</span><span class="br0">)</span> <span class="sy0">==</span> <span class="sy0">-</span><span class="nu0">1</span> <span class="br0">)</span> <span class="br0">{</span> |
|
604 <span class="co1">// Reconsider..</span> |
|
605 e.<span class="me1">preventDefault</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span> |
|
606 <span class="br0">}</span><span class="sy0">;</span> |
|
607 <span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span></pre></div><textarea id="syntax4-plain">// We can also listen before an attribute changes its value, and |
|
608 // decide if we want to allow the state change to occur or not. |
|
609 |
|
610 // Invoking e.preventDefault() stops the state from being updated. |
|
611 |
|
612 // In this case, Jane can change her mind about making herself |
|
613 // unavailable, if John likes saving whales, as long as he doesn't |
|
614 // dig knitting too. |
|
615 |
|
616 jane.on("availableChange", function(e) { |
|
617 var johnsInterests = john.get("interests"); |
|
618 var janeAvailable = e.newVal; |
|
619 |
|
620 if (janeAvailable === false && Y.Array.indexOf(johnsInterests, "Saving Whales") !== -1 |
|
621 && Y.Array.indexOf(johnsInterests, "Knitting") == -1 ) { |
|
622 // Reconsider.. |
|
623 e.preventDefault(); |
|
624 }; |
|
625 });</textarea></div> |
|
626 <p>We also set up an <em>"after"</em> listener on the <code>john</code> instance, which allows <code>jane</code> to update her interests, so she can admit to enjoying "Reading Specifications", if <code>john</code> admits it first:</p> |
|
627 |
|
628 <div id="syntax5" class="yui-syntax-highlight"><div class="numbers"><pre class="javascript" style="font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="co1">// Consider updating Jane's interests state, after John's interests </span></div></li><li class="li1"><div class="de1"><span class="co1">// state changes...</span></div></li><li class="li1"><div class="de1">john.<span class="me1">after</span><span class="br0">(</span><span class="st0">"interestsChange"</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li2"><div class="de2"> <span class="kw2">var</span> janesInterests <span class="sy0">=</span> jane.<span class="me1">get</span><span class="br0">(</span><span class="st0">"interests"</span><span class="br0">)</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="co1">// Get john's new interests from the attribute change event...</span></div></li><li class="li1"><div class="de1"> johnsInterests <span class="sy0">=</span> e.<span class="me1">newVal</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li2"><div class="de2"> readingSpecs <span class="sy0">=</span> <span class="st0">"Reading Specifications"</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="co1">// If it turns out that John enjoys reading specs, then Jane can admit it too...</span></div></li><li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">(</span>Y.<span class="me1">Array</span>.<span class="me1">indexOf</span><span class="br0">(</span>johnsInterests<span class="sy0">,</span> readingSpecs<span class="br0">)</span> <span class="sy0">!==</span> <span class="sy0">-</span><span class="nu0">1</span><span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw1">if</span><span class="br0">(</span>Y.<span class="me1">Array</span>.<span class="me1">indexOf</span><span class="br0">(</span>janesInterests<span class="sy0">,</span> readingSpecs<span class="br0">)</span> <span class="sy0">==</span> <span class="sy0">-</span><span class="nu0">1</span><span class="br0">)</span> <span class="br0">{</span></div></li><li class="li2"><div class="de2"> janesInterests.<span class="me1">push</span><span class="br0">(</span>readingSpecs<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span> <span class="kw1">else</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="co1">// Otherwise, we use Y.Array.reject, provided by the "collection" module, </span></div></li><li class="li1"><div class="de1"> <span class="co1">// to remove "Reading Specifications" from jane's interests..</span></div></li><li class="li2"><div class="de2"> janesInterests <span class="sy0">=</span> Y.<span class="me1">Array</span>.<span class="me1">reject</span><span class="br0">(</span>janesInterests<span class="sy0">,</span> </div></li><li class="li1"><div class="de1"> <span class="kw2">function</span><span class="br0">(</span><span class="kw1">item</span><span class="br0">)</span><span class="br0">{</span><span class="kw1">return</span> <span class="br0">(</span><span class="kw1">item</span> <span class="sy0">==</span> readingSpecs<span class="br0">)</span><span class="sy0">;</span><span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> jane.<span class="me1">set</span><span class="br0">(</span><span class="st0">"interests"</span><span class="sy0">,</span> janesInterests<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2"> jane.<span class="me1">set</span><span class="br0">(</span><span class="st0">"available"</span><span class="sy0">,</span> <span class="kw2">true</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> ...</div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span></div></li></ol></pre></div><div class="nonumbers"><pre class="javascript" style="font-family:monospace;"><span class="co1">// Consider updating Jane's interests state, after John's interests </span> |
|
629 <span class="co1">// state changes...</span> |
|
630 john.<span class="me1">after</span><span class="br0">(</span><span class="st0">"interestsChange"</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span> |
|
631 |
|
632 <span class="kw2">var</span> janesInterests <span class="sy0">=</span> jane.<span class="me1">get</span><span class="br0">(</span><span class="st0">"interests"</span><span class="br0">)</span><span class="sy0">,</span> |
|
633 |
|
634 <span class="co1">// Get john's new interests from the attribute change event...</span> |
|
635 johnsInterests <span class="sy0">=</span> e.<span class="me1">newVal</span><span class="sy0">,</span> |
|
636 |
|
637 readingSpecs <span class="sy0">=</span> <span class="st0">"Reading Specifications"</span><span class="sy0">;</span> |
|
638 |
|
639 <span class="co1">// If it turns out that John enjoys reading specs, then Jane can admit it too...</span> |
|
640 <span class="kw1">if</span> <span class="br0">(</span>Y.<span class="me1">Array</span>.<span class="me1">indexOf</span><span class="br0">(</span>johnsInterests<span class="sy0">,</span> readingSpecs<span class="br0">)</span> <span class="sy0">!==</span> <span class="sy0">-</span><span class="nu0">1</span><span class="br0">)</span> <span class="br0">{</span> |
|
641 <span class="kw1">if</span><span class="br0">(</span>Y.<span class="me1">Array</span>.<span class="me1">indexOf</span><span class="br0">(</span>janesInterests<span class="sy0">,</span> readingSpecs<span class="br0">)</span> <span class="sy0">==</span> <span class="sy0">-</span><span class="nu0">1</span><span class="br0">)</span> <span class="br0">{</span> |
|
642 janesInterests.<span class="me1">push</span><span class="br0">(</span>readingSpecs<span class="br0">)</span><span class="sy0">;</span> |
|
643 <span class="br0">}</span> |
|
644 <span class="br0">}</span> <span class="kw1">else</span> <span class="br0">{</span> |
|
645 <span class="co1">// Otherwise, we use Y.Array.reject, provided by the "collection" module, </span> |
|
646 <span class="co1">// to remove "Reading Specifications" from jane's interests..</span> |
|
647 janesInterests <span class="sy0">=</span> Y.<span class="me1">Array</span>.<span class="me1">reject</span><span class="br0">(</span>janesInterests<span class="sy0">,</span> |
|
648 <span class="kw2">function</span><span class="br0">(</span><span class="kw1">item</span><span class="br0">)</span><span class="br0">{</span><span class="kw1">return</span> <span class="br0">(</span><span class="kw1">item</span> <span class="sy0">==</span> readingSpecs<span class="br0">)</span><span class="sy0">;</span><span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span> |
|
649 <span class="br0">}</span> |
|
650 |
|
651 jane.<span class="me1">set</span><span class="br0">(</span><span class="st0">"interests"</span><span class="sy0">,</span> janesInterests<span class="br0">)</span><span class="sy0">;</span> |
|
652 jane.<span class="me1">set</span><span class="br0">(</span><span class="st0">"available"</span><span class="sy0">,</span> <span class="kw2">true</span><span class="br0">)</span><span class="sy0">;</span> |
|
653 |
|
654 ... |
|
655 <span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span></pre></div><textarea id="syntax5-plain">// Consider updating Jane's interests state, after John's interests |
|
656 // state changes... |
|
657 john.after("interestsChange", function(e) { |
|
658 |
|
659 var janesInterests = jane.get("interests"), |
|
660 |
|
661 // Get john's new interests from the attribute change event... |
|
662 johnsInterests = e.newVal, |
|
663 |
|
664 readingSpecs = "Reading Specifications"; |
|
665 |
|
666 // If it turns out that John enjoys reading specs, then Jane can admit it too... |
|
667 if (Y.Array.indexOf(johnsInterests, readingSpecs) !== -1) { |
|
668 if(Y.Array.indexOf(janesInterests, readingSpecs) == -1) { |
|
669 janesInterests.push(readingSpecs); |
|
670 } |
|
671 } else { |
|
672 // Otherwise, we use Y.Array.reject, provided by the "collection" module, |
|
673 // to remove "Reading Specifications" from jane's interests.. |
|
674 janesInterests = Y.Array.reject(janesInterests, |
|
675 function(item){return (item == readingSpecs);}); |
|
676 } |
|
677 |
|
678 jane.set("interests", janesInterests); |
|
679 jane.set("available", true); |
|
680 |
|
681 ... |
|
682 });</textarea></div> |
|
683 <h4>Event Facade</h4> |
|
684 |
|
685 <p>The event object (an instance of <a href="../../api/EventFacade.html">EventFacade</a>) passed to attribute change event subscribers, has the following interesting properties and methods related to attribute management:</p> |
|
686 |
|
687 <dl> |
|
688 <dt>newVal</dt> |
|
689 <dd>The value which the attribute will be set to (in the case of <em>"on"</em> subscribers), or has been set to (in the case of <em>"after"</em> subscribers</dd> |
|
690 <dt>prevVal</dt> |
|
691 <dd>The value which the attribute is currently set to (in the case of <em>"on"</em> subscribers), or was previously set to (in the case of <em>"after"</em> subscribers</dd> |
|
692 <dt>attrName</dt> |
|
693 <dd>The name of the attribute which is being set</dd> |
|
694 <dt>subAttrName</dt> |
|
695 <dd>Attribute also allows you to set nested properties of attributes which have values which are objects through the |
|
696 <code>set</code> method (e.g. <code>o1.set("x.y.z")</code>). This property will contain the path to the property which was changed.</dd> |
|
697 <dt>preventDefault()<dt> |
|
698 <dd>This method can be called in an <em>"on"</em> subscriber to prevent the attribute's value from being updated (the default behavior). Calling this method in an <em>"after"</em> listener has no impact, since the default behavior has already been invoked.</dd> |
|
699 <dt>stopImmediatePropagation()</dt> |
|
700 <dd>This method can be called in <em>"on"</em> or <em>"after"</em> subscribers, and will prevent the rest of the subscriber stack from |
|
701 being invoked, but will not prevent the attribute's value from being updated.</dd> |
|
702 </dl> |
|
703 </div> |
|
704 <div class="yui-u sidebar"> |
|
705 |
|
706 |
|
707 <div id="examples" class="mod box4"> |
|
708 <div class="hd"> |
|
709 <h4> |
|
710 Attribute Examples:</h4> |
|
711 </div> |
|
712 <div class="bd"> |
|
713 <ul> |
|
714 <li><a href='../attribute/attribute-basic.html'>Basic Attribute Configuration</a></li><li><a href='../attribute/attribute-rw.html'>Read-Only and Write-Once Attributes</a></li><li><a href='../attribute/attribute-event.html'>Attribute Change Events</a></li><li><a href='../attribute/attribute-basic-speeddate.html'>Attribute Based Speed Dating</a></li><li class='selected'><a href='../attribute/attribute-event-speeddate.html'>Attribute Event Based Speed Dating</a></li><li><a href='../attribute/attribute-getset.html'>Attribute Getters, Setters and Validators</a></li> </ul> |
|
715 </div> |
|
716 </div> |
|
717 |
|
718 <div class="mod box4"> |
|
719 <div class="hd"> |
|
720 <h4>More Attribute Resources:</h4> |
|
721 </div> |
|
722 <div class="bd"> |
|
723 <ul> |
|
724 <!-- <li><a href="http://developer.yahoo.com/yui/attribute/">User's Guide</a> (external)</li> --> |
|
725 <li><a href="../../api/module_attribute.html">API Documentation</a></li></ul> |
|
726 </div> |
|
727 </div> |
|
728 </div> |
|
729 </div> |
|
730 |
|
731 </div> |
|
732 </div> |
|
733 |
|
734 |
|
735 <div class="yui-b toc3" id="tocWrapper"> |
|
736 <!-- TABLE OF CONTENTS --> |
|
737 <div id="toc"> |
|
738 |
|
739 <ul> |
|
740 <li class="sect first">YUI 3 Resources</li><li class="item"><a title="YUI 3 -- Yahoo! User Interface (YUI) Library" href="http://developer.yahoo.com/yui/3/">YUI 3 Web Site</a></li><li class="item"><a title="Examples of every YUI utility and control in action" href="../../examples/">YUI 3 Examples</a></li><li class="item"><a title="Instantly searchable API documentation for the entire YUI library." href="../../api/">YUI 3 API Docs</a></li><li class="item"><a title="YUI 3 Dependency Configurator -- configure your custom YUI implementation" href="http://developer.yahoo.com/yui/3/configurator">YUI 3 Dependency Configurator</a></li><li class="item"><a title="The YUI 3 Forum on YUILibrary.com" href="http://yuilibrary.com/forum/viewforum.php?f=15">YUI 3 Forums (external)</a></li><li class="item"><a title="Found a bug or a missing feature? Let us know on YUILibrary.com." href="http://developer.yahoo.com/yui/articles/reportingbugs/">Bug Reports/Feature Requests</a></li><li class="item"><a title="YUI is free and open, offered under a BSD license." href="http://developer.yahoo.com/yui/license.html">YUI License</a></li><li class="item"><a title="Download and fork the YUI project on GitHub" href="http://github.com/yui">YUI on Github</a></li><li class="item"><a title="The Yahoo! User Interface Blog" href="http://yuiblog.com">YUI Blog (external)</a></li><li class="sect">YUI 3 Core - Examples</li><li class="item"><a title="YUI Global Object - Functional Examples" href="../../examples/yui/index.html">YUI Global Object</a></li><li class="item"><a title="Event - Functional Examples" href="../../examples/event/index.html">Event</a></li><li class="item"><a title="Node - Functional Examples" href="../../examples/node/index.html">Node</a></li><li class="sect">YUI 3 Component Infrastructure - Examples</li><li class="selected "><a title="Attribute - Functional Examples" href="../../examples/attribute/index.html">Attribute</a></li><li class="item"><a title="Plugin - Functional Examples" href="../../examples/plugin/index.html">Plugin <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="item"><a title="Widget - Functional Examples" href="../../examples/widget/index.html">Widget <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="sect">YUI 3 Utilities - Examples</li><li class="item"><a title="Animation - Functional Examples" href="../../examples/anim/index.html">Animation</a></li><li class="item"><a title="AsyncQueue - Functional Examples" href="../../examples/async-queue/index.html">AsyncQueue</a></li><li class="item"><a title="Browser History - Functional Examples" href="../../examples/history/index.html">Browser History</a></li><li class="item"><a title="Cache - Functional Examples" href="../../examples/cache/index.html">Cache</a></li><li class="item"><a title="Cookie - Functional Examples" href="../../examples/cookie/index.html">Cookie</a></li><li class="item"><a title="DataSchema - Functional Examples" href="../../examples/dataschema/index.html">DataSchema <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="item"><a title="DataSource - Functional Examples" href="../../examples/datasource/index.html">DataSource <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="item"><a title="DataType - Functional Examples" href="../../examples/datatype/index.html">DataType <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="item"><a title="Drag & Drop - Functional Examples" href="../../examples/dd/index.html">Drag & Drop</a></li><li class="item"><a title="Get - Functional Examples" href="../../examples/get/index.html">Get</a></li><li class="item"><a title="ImageLoader - Functional Examples" href="../../examples/imageloader/index.html">ImageLoader</a></li><li class="item"><a title="IO - Functional Examples" href="../../examples/io/index.html">IO</a></li><li class="item"><a title="JSON (JavaScript Object Notation) - Functional Examples" href="../../examples/json/index.html">JSON</a></li><li class="item"><a title="Stylesheet - Functional Examples" href="../../examples/stylesheet/index.html">Stylesheet</a></li><li class="sect">YUI 3 Widgets - Examples</li><li class="item"><a title="Overlay - Functional Examples" href="../../examples/overlay/index.html">Overlay <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="item"><a title="Slider - Functional Examples" href="../../examples/slider/index.html">Slider <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="sect">YUI 3 Node Plugins - Examples</li><li class="item"><a title="FocusManager Node Plugin - Functional Examples" href="../../examples/node-focusmanager/index.html">FocusManager Node Plugin <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="item"><a title="MenuNav Node Plugin - Functional Examples" href="../../examples/node-menunav/index.html">MenuNav Node Plugin <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="sect">YUI 3 CSS - Examples</li><li class="item"><a title="YUI CSS Reset - Functional Examples" href="../../examples/cssreset/index.html">CSS Reset</a></li><li class="item"><a title="YUI Fonts - Functional Examples" href="../../examples/cssfonts/index.html">CSS Fonts</a></li><li class="item"><a title="YUI Base - Functional Examples" href="../../examples/cssbase/index.html">CSS Base</a></li><li class="sect">YUI 3 Developer Tools - Examples</li><li class="item"><a title="Console - Functional Examples" href="../../examples/console/index.html">Console <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="item"><a title="Console Filters Plugin- Functional Examples" href="../../examples/console-filters/index.html">Plugin.ConsoleFilters <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="item"><a title="Profiler - Functional Examples" href="../../examples/profiler/index.html">Profiler</a></li><li class="item"><a title="Test - Functional Examples" href="../../examples/test/index.html">Test</a></li><li class="sect">Other Useful YUI 3 Resources</li><li class="item"><a title="Answers to Frequently Asked Questions about the YUI Library" href="http://developer.yahoo.com/yui/articles/faq/">YUI FAQ (external)</a></li><li class="item"><a title="Yahoo!'s philosophy of Graded Browser Support" href="http://developer.yahoo.com/yui/articles/gbs/">Graded Browser Support (external)</a></li><li class="item"><a title="Videos and podcasts from the YUI Team and from the Yahoo! frontend engineering community." href="http://developer.yahoo.com/yui/theater/">YUI Theater (external)</a></li></ul> |
|
741 </div> |
|
742 </div> |
|
743 </div><!--closes bd--> |
|
744 |
|
745 <div id="ft"> |
|
746 <p class="first">Copyright © 2009 Yahoo! Inc. All rights reserved.</p> |
|
747 <p><a href="http://privacy.yahoo.com/privacy/us/devel/index.html">Privacy Policy</a> - |
|
748 <a href="http://docs.yahoo.com/info/terms/">Terms of Service</a> - |
|
749 <a href="http://docs.yahoo.com/info/copyright/copyright.html">Copyright Policy</a> - |
|
750 <a href="http://careers.yahoo.com/">Job Openings</a></p> |
|
751 </div> |
|
752 </div> |
|
753 <script language="javascript"> |
|
754 var yuiConfig = {base:"../../build/", timeout: 10000}; |
|
755 </script> |
|
756 <script src="../../assets/syntax.js"></script> |
|
757 <script src="../../assets/dpSyntaxHighlighter.js"></script> |
|
758 <script language="javascript"> |
|
759 dp.SyntaxHighlighter.HighlightAll('code'); |
|
760 </script> |
|
761 </body> |
|
762 </html> |