5
<title>Example: Attribute Getters, Setters and Validators</title>
6
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Maven+Pro:400,700">
7
<link rel="stylesheet" href="../../build/cssgrids/grids-min.css">
8
<link rel="stylesheet" href="../assets/css/main.css">
9
<link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css">
10
<script src="../../build/yui/yui-min.js"></script>
15
<h1>Example: Attribute Getters, Setters and Validators</h1>
20
<div class="yui3-u-3-4">
22
<div class="content"><style type="text/css" scoped>
26
background-color:#004c6d;
32
#boxParent .yui3-box p, #attrs p {
37
border:1px solid #000;
38
background-color:#cdcdcd;
44
background-color:#aaa;
52
.attrs .body .hints li {
57
padding:0px 20px 10px 20px;
73
border-top:1px solid #aaa;
79
border:1px solid #000;
86
.yui3-box .color, .yui3-box .coord {
93
<p>The <a href="attribute-basic.html">"Basic Attribute Configuration" example</a> shows how you can add attributes to a host class, and set up default values for them using the attribute configuration object. This example explores how you can configure <code>setter</code>, <code>getter</code> and <code>validator</code> functions for individual attributes, which can be used to modify or normalize attribute values during get and set invocations, and prevent invalid values from being stored.</p>
97
<div id="attrs" class="attrs">
98
<div class="header">Enter new values and click the "Set" buttons</div>
101
<li>Try entering valid and invalid values for x, y; or values which attempt to position the box outside it's parent (parent box co-ordinates are displayed next to the text box).</li>
102
<li>Try entering rgb, hex or keyword color values [ <code>rgb(255,0,0)</code>, <code>#ff0000</code>, <code>red</code> ].</li>
106
<form action="#" id="setX" class="action">
107
<label for="x">x:</label>
108
<input type="text" name="x" id="x" />
109
<button type="submit">Set</button>
110
<span id="xhint" class="hint"></span>
114
<form action="#" id="setY" class="action">
115
<label for="y">y:</label>
116
<input type="text" name="y" id="y" />
117
<button type="submit">Set</button>
118
<span id="yhint" class="hint"></span>
122
<form action="#" id="setColor" class="action">
123
<label for="color">color:</label>
124
<input type="text" name="color" id="color" />
125
<button type="submit">Set</button>
131
<button type="button" class="action" id="setXY">Set XY</button>
132
<button type="button" class="action" id="setAll">Set All</button>
133
<button type="button" class="action" id="getAll">Get All</button>
137
<div id="boxParent"></div>
139
<script type="text/javascript">
140
// Get a new YUI instance
141
YUI().use("node", "attribute", function(Y) {
143
var boxParent = Y.one("#boxParent");
145
// Setup a custom class with attribute support
147
this._createNode(cfg);
149
// Attribute configuration
157
setter: function(val, name) {
158
// Pass through x value to xy
159
this.set("xy", [parseInt(val), this.get("y")]);
162
getter: function(val, name) {
163
// Get x value from xy
164
return this.get("xy")[0];
169
setter: function(val, name) {
170
// Pass through y value to xy
171
this.set("xy", [this.get("x"), parseInt(val)]);
175
// Get y value from xy
176
return this.get("xy")[1];
181
// Actual stored xy co-ordinates
184
setter: function(val, name) {
185
// Constrain XY value to the parent element.
187
// Returns the constrained xy value, which will
188
// be the final value stored.
189
return this.constrain(val);
192
validator: function(val, name) {
193
// Ensure we only store a valid data value
194
return (Y.Lang.isArray(val) && val.length == 2 && Y.Lang.isNumber(val[0]) && Y.Lang.isNumber(val[1]));
201
getter: function(val, name) {
202
// Always normalize the returned value to
203
// a hex color value, even if the stored
204
// value is a keyword, or an rgb value.
206
return Y.Color.toHex(val);
212
validator: function(val, name) {
213
// Ensure we only store rgb, hex or keyword values.
214
return (Y.Color.re_RGB.test(val) || Y.Color.re_hex.test(val) || Y.Color.KEYWORDS[val]);
219
this.addAttrs(attrs, cfg);
227
// Create the box node
228
Box.prototype._createNode = function() {
229
this._node = Y.Node.create('<div class="yui3-box"><p>Positioned Box</p><p class="coord"></p><p class="color">None</p></div>');
232
// Update rendered state to match the attribute state
233
Box.prototype._sync = function() {
239
Box.prototype._syncParent = function() {
240
this.get("parent").appendChild(this._node);
243
Box.prototype._syncXY = function() {
244
this._node.setXY(this.get("xy"));
245
this._node.one("p.coord").set("innerHTML", "[" + this.get("x") + "," + this.get("y") + "]");
248
Box.prototype._syncColor = function() {
249
this._node.setStyle("backgroundColor", this.get("color"));
250
this._node.one("p.color").set("innerHTML", this.get("color"));
253
// Bind listeners for attribute change events
254
Box.prototype._bind = function() {
256
// Reflect any changes in xy, to the rendered Node
257
this.after("xyChange", this._syncXY);
259
// Reflect any changes in color, to the rendered Node
260
// and output the color value received from get
261
this.after("colorChange", this._syncColor);
263
// Append the rendered node to the parent provided
264
this.after("parentChange", this._syncParent);
268
// Get min, max unconstrained values for X. Using Math.round to handle FF3's sub-pixel region values
269
Box.prototype.getXConstraints = function() {
270
var parentRegion = this.get("parent").get("region");
271
return [Math.round(parentRegion.left + Box.BUFFER), Math.round(parentRegion.right - this._node.get("offsetWidth") - Box.BUFFER)];
274
// Get min, max unconstrained values for Y. Using Math.round to handle FF3's sub-pixel region values
275
Box.prototype.getYConstraints = function() {
276
var parentRegion = this.get("parent").get("region");
277
return [Math.round(parentRegion.top + Box.BUFFER), Math.round(parentRegion.bottom - this._node.get("offsetHeight") - Box.BUFFER)];
280
// Constrain the x,y value provided
281
Box.prototype.constrain = function(val) {
283
// If the X value places the box outside it's parent,
284
// modify it's value to place the box inside it's parent.
286
var xConstraints = this.getXConstraints();
288
if (val[0] < xConstraints[0]) {
289
val[0] = xConstraints[0];
291
if (val[0] > xConstraints[1]) {
292
val[0] = xConstraints[1];
296
// If the Y value places the box outside it's parent,
297
// modify it's value to place the box inside it's parent.
299
var yConstraints = this.getYConstraints();
301
if (val[1] < yConstraints[0]) {
302
val[1] = yConstraints[0];
304
if (val[1] > yConstraints[1]) {
305
val[1] = yConstraints[1];
313
Y.augment(Box, Y.Attribute);
317
// Create a new instance of Box
322
// Set references to form controls
323
var xTxt = Y.one("#x");
324
var yTxt = Y.one("#y");
325
var colorTxt = Y.one("#color");
327
var xHint = Y.one("#xhint");
328
var yHint = Y.one("#yhint");
331
xTxt.set("value", box.get("x"));
332
yTxt.set("value", box.get("y"));
333
colorTxt.set("value", box.get("color"));
336
// Use event delegation for the action button clicks, and form submissions
337
Y.delegate("click", function(e) {
339
// Get Node target from the event object
341
// We already know it's a button which has an action because
342
// of our selector (button.action), so all we need to do is
343
// route it based on the id.
344
var id = e.currentTarget.get("id");
348
box.set("xy", [parseInt(xTxt.get("value")), parseInt(yTxt.get("value"))]);
351
box.set("xy", [parseInt(xTxt.get("value")), parseInt(yTxt.get("value"))]);
352
box.set("color", Y.Lang.trim(colorTxt.get("value")));
361
}, "#attrs", "button.action");
363
Y.all("#attrs form.action").on("submit", function(e) {
367
// Get Node target from the event object
369
// We already know it's a button which has an action because
370
// of our selector (button.action), so all we need to do is
371
// route it based on the id.
372
var id = e.currentTarget.get("id");
376
box.set("x", parseInt(xTxt.get("value")));
379
box.set("y", parseInt(yTxt.get("value")));
382
box.set("color", Y.Lang.trim(colorTxt.get("value")));
389
// Bind listeners to provide min, max unconstrained value hints for x, y
390
// (focus/blur doesn't bubble, so bind individual listeners)
391
Y.on("focus", function() {
392
var minmax = box.getXConstraints();
393
xHint.set("innerHTML", "Valid values: " + minmax[0] + " to " + minmax[1]);
396
Y.on("focus", function() {
397
var minmax = box.getYConstraints();
398
yHint.set("innerHTML", "Valid values: " + minmax[0] + " to " + minmax[1]);
401
Y.on("blur", function() {
402
xHint.set("innerHTML", "");
405
Y.on("blur", function() {
406
yHint.set("innerHTML", "");
415
<h2>Getter, Setter And Validator Functions</h2>
417
<p>Attribute lets you configure <code>getter</code> and <code>setter</code> functions for each attribute. These functions are invoked when the user calls Attribute's <code>get</code> and <code>set</code> methods, and provide a way to modify the value returned or the value stored respectively.</p>
419
<p>You can also define a <code>validator</code> function for each attribute, which is used to validate the final value before it gets stored.</p>
421
<p>All these functions receive the value and name of the attribute being set or retrieved, as shown in the example code below. The name is not used in this example, but is provided to support use cases where you may wish to share the same function between different attributes.</p>
423
<h3>Creating The Box Class - The X, Y And XY Attributes</h3>
425
<p>In this example, we'll set up a custom <code>Box</code> class representing a positionable element, with <code>x</code>, <code>y</code> and <code>xy</code> attributes.</p>
427
<p>Only the <code>xy</code> attribute will actually store the page co-ordinate position of the box. The <code>x</code> and <code>y</code> attributes provide the user a convenient way to set only one of the co-ordinates.
428
However we don't want to store the actual values in the <code>x</code> and <code>y</code> attributes, to avoid having to constantly synchronize all three.
430
The <code>getter</code> and <code>setter</code> functions provide us with an easy way to achieve this. We'll define <code>getter</code> and <code>setter</code> functions for both the <code>x</code> and <code>y</code> attributes, which simply pass through to the <code>xy</code> attribute to store and retrieve values:</p>
432
<pre class="code prettyprint">// Setup a custom class with attribute support
437
// Attribute configuration
440
"parent" : {
445
setter: function(val, name) {
446
// Pass through x value to xy
447
this.set("xy", [parseInt(val), this.get("y")]);
450
getter: function(val, name) {
451
// Get x value from xy
452
return this.get("xy")[0];
457
setter: function(val, name) {
458
// Pass through y value to xy
459
this.set("xy", [this.get("x"), parseInt(val)]);
463
// Get y value from xy
464
return this.get("xy")[1];
469
// Actual stored xy co-ordinates
472
setter: function(val, name) {
473
// Constrain XY value to the parent element.
475
// Returns the constrained xy value, which will
476
// be the final value stored.
477
return this.constrain(val);
480
validator: function(val, name) {
481
// Ensure we only store a valid data value
482
return (Y.Lang.isArray(val) &&
483
val.length == 2 &&
484
Y.Lang.isNumber(val[0]) && Y.Lang.isNumber(val[1]));
490
this.addAttrs(attrs, cfg);
496
<p>The <code>validator</code> function for <code>xy</code> ensures that only valid values finally end up being stored.</p>
498
<p>The <code>xy</code> attribute also has a <code>setter</code> function configured, which makes sure that the box is always constrained to it's parent element. The <code>constrain</code> method which it delegates to, takes the xy value the user is trying to set and returns a constrained value if the x or y values fall outside the parent box. The value which is returned by the <code>setter</code> is the value which is ultimately stored for the <code>xy</code> attribute:</p>
500
<pre class="code prettyprint">// Get min, max unconstrained values for X.
501
// Using Math.round to handle FF3's sub-pixel region values
502
Box.prototype.getXConstraints = function() {
503
var parentRegion = this.get("parent").get("region");
504
return [Math.round(parentRegion.left + Box.BUFFER),
505
Math.round(parentRegion.right - this._node.get("offsetWidth") - Box.BUFFER)];
508
// Get min, max unconstrained values for Y.
509
// Using Math.round to handle FF3's sub-pixel region values
510
Box.prototype.getYConstraints = function() {
511
var parentRegion = this.get("parent").get("region");
512
return [Math.round(parentRegion.top + Box.BUFFER),
513
Math.round(parentRegion.bottom - this._node.get("offsetHeight") - Box.BUFFER)];
516
// Constrains given x,y values
517
Box.prototype.constrain = function(val) {
519
// If the X value places the box outside it's parent,
520
// modify it's value to place the box inside it's parent.
522
var xConstraints = this.getXConstraints();
524
if (val[0] < xConstraints[0]) {
525
val[0] = xConstraints[0];
527
if (val[0] > xConstraints[1]) {
528
val[0] = xConstraints[1];
532
// If the Y value places the box outside it's parent,
533
// modify it's value to place the box inside it's parent.
535
var yConstraints = this.getYConstraints();
537
if (val[1] < yConstraints[0]) {
538
val[1] = yConstraints[0];
540
if (val[1] > yConstraints[1]) {
541
val[1] = yConstraints[1];
549
<p>The <code>setter</code>, <code>getter</code> and <code>validator</code> functions are invoked with the host object as the context, so that they can refer to the host object using "<code>this</code>", as we see in the <code>setter</code> function for <code>xy</code>.</p>
551
<h3>The Color Attribute - Normalizing Stored Values Through Get</h3>
553
<p>The <code>Box</code> class also has a <code>color</code> attribute which also has a <code>getter</code> and <code>validator</code> functions defined:</p>
555
<pre class="code prettyprint">...
556
"color" : {
557
value: "olive",
559
getter: function(val, name) {
561
return Y.Color.toHex(val);
567
validator: function(val, name) {
568
return (Y.Color.re_RGB.test(val) || Y.Color.re_hex.test(val)
569
|| Y.Color.KEYWORDS[val]);
575
<p>The role of the <code>getter</code> handler in this case is to normalize the actual stored value of the <code>color</code> attribute, so that users always receive the hex value, regardless of the actual value stored, which maybe a color keyword (e.g. <code>"red"</code>), an rgb value (e.g.<code>rbg(255,0,0)</code>), or a hex value (<code>#ff0000</code>). The <code>validator</code> ensures the the stored value is one of these three formats.</p>
577
<h3>Syncing Changes Using Attribute Change Events</h3>
579
<p>Another interesting aspect of this example, is it's use of attribute change events to listen for changes to the attribute values. <code>Box</code>'s <code>_bind</code> method configures a set of attribute change event listeners which monitor changes to the <code>xy</code>, <code>color</code> and <code>parent</code> attributes and update the rendered DOM for the Box in response:</p>
581
<pre class="code prettyprint">// Bind listeners for attribute change events
582
Box.prototype._bind = function() {
584
// Reflect any changes in xy, to the rendered Node
585
this.after("xyChange", this._syncXY);
587
// Reflect any changes in color, to the rendered Node
588
// and output the color value received from get
589
this.after("colorChange", this._syncColor);
591
// Append the rendered node to the parent provided
592
this.after("parentChange", this._syncParent);
597
<p>Since only <code>xy</code> stores the final co-ordinates, we don't need to monitor the <code>x</code> and <code>y</code> attributes individually for changes.</p>
599
<h3>DOM Event Listeners And Delegation</h3>
601
<p>Although not an integral part of the example, it's worth highlighting the code which is used to setup the DOM event listeners for the form elements used by the example:</p>
603
<pre class="code prettyprint">// Set references to form controls
604
var xTxt = Y.one("#x");
605
var yTxt = Y.one("#y");
606
var colorTxt = Y.one("#color");
608
// Use event delegation for the action button clicks, and form submissions
609
Y.delegate("click", function(e) {
611
// Get Node target from the event object
613
// We already know it's a button which has an action because
614
// of our selector (button.action), so all we need to do is
615
// route it based on the id.
616
var id = e.currentTarget.get("id");
619
case "setXY":
620
box.set("xy", [parseInt(xTxt.get("value")), parseInt(yTxt.get("value"))]);
622
case "setAll":
623
box.set("xy", [parseInt(xTxt.get("value")), parseInt(yTxt.get("value"))]);
624
box.set("color", Y.Lang.trim(colorTxt.get("value")));
626
case "getAll":
633
}, "#attrs", "button.action");</pre>
635
<p>Rather than attach individual listeners to each button, the above code uses YUI 3's <code>delegate</code> support, to listen for <code>click</code> from buttons, with an <code>action</code> class which bubble up to the <code>attrs</code> element.</p>
636
<p>The delegate listener uses the <a href="http://yuilibrary.com/yui/docs/api/DOMEventFacade.html">Event Facade</a> which normalizes cross-browser access to DOM event properties, such as <code>currentTarget</code>, to route to the appropriate button handler. Note the use of selector syntax when we specify the elements for the listener (e.g. <code>#attrs</code>, <code>button.actions</code>) and the use of the <a href="http://yuilibrary.com/yui/docs/api/Node.html">Node</a> facade when dealing with references to HTML elements (e.g. <code>xTxt, yTxt, colorTxt</code>).</p>
638
<h2>Complete Example Source</h2>
640
<pre class="code prettyprint"><div id="attrs" class="attrs">
641
<div class="header">Enter new values and click the "Set" buttons</div>
642
<div class="body">
643
<ul class="hints">
644
<li>Try entering valid and invalid values for x, y; or values which attempt to position the box outside it's parent (parent box co-ordinates are displayed next to the text box).</li>
645
<li>Try entering rgb, hex or keyword color values [ <code>rgb(255,0,0)</code>, <code>#ff0000</code>, <code>red</code> ].</li>
647
<div class="fields">
649
<form action="#" id="setX" class="action">
650
<label for="x">x:</label>
651
<input type="text" name="x" id="x" />
652
<button type="submit">Set</button>
653
<span id="xhint" class="hint"></span>
657
<form action="#" id="setY" class="action">
658
<label for="y">y:</label>
659
<input type="text" name="y" id="y" />
660
<button type="submit">Set</button>
661
<span id="yhint" class="hint"></span>
665
<form action="#" id="setColor" class="action">
666
<label for="color">color:</label>
667
<input type="text" name="color" id="color" />
668
<button type="submit">Set</button>
673
<div class="footer">
674
<button type="button" class="action" id="setXY">Set XY</button>
675
<button type="button" class="action" id="setAll">Set All</button>
676
<button type="button" class="action" id="getAll">Get All</button>
680
<div id="boxParent"></div>
682
<script type="text/javascript">
683
// Get a new YUI instance
684
YUI().use("node", "attribute", function(Y) {
686
var boxParent = Y.one("#boxParent");
688
// Setup a custom class with attribute support
690
this._createNode(cfg);
692
// Attribute configuration
695
"parent" : {
700
setter: function(val, name) {
701
// Pass through x value to xy
702
this.set("xy", [parseInt(val), this.get("y")]);
705
getter: function(val, name) {
706
// Get x value from xy
707
return this.get("xy")[0];
712
setter: function(val, name) {
713
// Pass through y value to xy
714
this.set("xy", [this.get("x"), parseInt(val)]);
718
// Get y value from xy
719
return this.get("xy")[1];
724
// Actual stored xy co-ordinates
727
setter: function(val, name) {
728
// Constrain XY value to the parent element.
730
// Returns the constrained xy value, which will
731
// be the final value stored.
732
return this.constrain(val);
735
validator: function(val, name) {
736
// Ensure we only store a valid data value
737
return (Y.Lang.isArray(val) && val.length == 2 && Y.Lang.isNumber(val[0]) && Y.Lang.isNumber(val[1]));
741
"color" : {
742
value: "olive",
744
getter: function(val, name) {
745
// Always normalize the returned value to
746
// a hex color value, even if the stored
747
// value is a keyword, or an rgb value.
749
return Y.Color.toHex(val);
755
validator: function(val, name) {
756
// Ensure we only store rgb, hex or keyword values.
757
return (Y.Color.re_RGB.test(val) || Y.Color.re_hex.test(val) || Y.Color.KEYWORDS[val]);
762
this.addAttrs(attrs, cfg);
770
// Create the box node
771
Box.prototype._createNode = function() {
772
this._node = Y.Node.create('<div class="yui3-box"><p>Positioned Box</p><p class="coord"></p><p class="color">None</p></div>');
775
// Update rendered state to match the attribute state
776
Box.prototype._sync = function() {
782
Box.prototype._syncParent = function() {
783
this.get("parent").appendChild(this._node);
786
Box.prototype._syncXY = function() {
787
this._node.setXY(this.get("xy"));
788
this._node.one("p.coord").set("innerHTML", "[" + this.get("x") + "," + this.get("y") + "]");
791
Box.prototype._syncColor = function() {
792
this._node.setStyle("backgroundColor", this.get("color"));
793
this._node.one("p.color").set("innerHTML", this.get("color"));
796
// Bind listeners for attribute change events
797
Box.prototype._bind = function() {
799
// Reflect any changes in xy, to the rendered Node
800
this.after("xyChange", this._syncXY);
802
// Reflect any changes in color, to the rendered Node
803
// and output the color value received from get
804
this.after("colorChange", this._syncColor);
806
// Append the rendered node to the parent provided
807
this.after("parentChange", this._syncParent);
811
// Get min, max unconstrained values for X. Using Math.round to handle FF3's sub-pixel region values
812
Box.prototype.getXConstraints = function() {
813
var parentRegion = this.get("parent").get("region");
814
return [Math.round(parentRegion.left + Box.BUFFER), Math.round(parentRegion.right - this._node.get("offsetWidth") - Box.BUFFER)];
817
// Get min, max unconstrained values for Y. Using Math.round to handle FF3's sub-pixel region values
818
Box.prototype.getYConstraints = function() {
819
var parentRegion = this.get("parent").get("region");
820
return [Math.round(parentRegion.top + Box.BUFFER), Math.round(parentRegion.bottom - this._node.get("offsetHeight") - Box.BUFFER)];
823
// Constrain the x,y value provided
824
Box.prototype.constrain = function(val) {
826
// If the X value places the box outside it's parent,
827
// modify it's value to place the box inside it's parent.
829
var xConstraints = this.getXConstraints();
831
if (val[0] < xConstraints[0]) {
832
val[0] = xConstraints[0];
834
if (val[0] > xConstraints[1]) {
835
val[0] = xConstraints[1];
839
// If the Y value places the box outside it's parent,
840
// modify it's value to place the box inside it's parent.
842
var yConstraints = this.getYConstraints();
844
if (val[1] < yConstraints[0]) {
845
val[1] = yConstraints[0];
847
if (val[1] > yConstraints[1]) {
848
val[1] = yConstraints[1];
856
Y.augment(Box, Y.Attribute);
860
// Create a new instance of Box
865
// Set references to form controls
866
var xTxt = Y.one("#x");
867
var yTxt = Y.one("#y");
868
var colorTxt = Y.one("#color");
870
var xHint = Y.one("#xhint");
871
var yHint = Y.one("#yhint");
874
xTxt.set("value", box.get("x"));
875
yTxt.set("value", box.get("y"));
876
colorTxt.set("value", box.get("color"));
879
// Use event delegation for the action button clicks, and form submissions
880
Y.delegate("click", function(e) {
882
// Get Node target from the event object
884
// We already know it's a button which has an action because
885
// of our selector (button.action), so all we need to do is
886
// route it based on the id.
887
var id = e.currentTarget.get("id");
890
case "setXY":
891
box.set("xy", [parseInt(xTxt.get("value")), parseInt(yTxt.get("value"))]);
893
case "setAll":
894
box.set("xy", [parseInt(xTxt.get("value")), parseInt(yTxt.get("value"))]);
895
box.set("color", Y.Lang.trim(colorTxt.get("value")));
897
case "getAll":
904
}, "#attrs", "button.action");
906
Y.all("#attrs form.action").on("submit", function(e) {
910
// Get Node target from the event object
912
// We already know it's a button which has an action because
913
// of our selector (button.action), so all we need to do is
914
// route it based on the id.
915
var id = e.currentTarget.get("id");
918
case "setX":
919
box.set("x", parseInt(xTxt.get("value")));
921
case "setY":
922
box.set("y", parseInt(yTxt.get("value")));
924
case "setColor":
925
box.set("color", Y.Lang.trim(colorTxt.get("value")));
932
// Bind listeners to provide min, max unconstrained value hints for x, y
933
// (focus/blur doesn't bubble, so bind individual listeners)
934
Y.on("focus", function() {
935
var minmax = box.getXConstraints();
936
xHint.set("innerHTML", "Valid values: " + minmax[0] + " to " + minmax[1]);
939
Y.on("focus", function() {
940
var minmax = box.getYConstraints();
941
yHint.set("innerHTML", "Valid values: " + minmax[0] + " to " + minmax[1]);
944
Y.on("blur", function() {
945
xHint.set("innerHTML", "");
948
Y.on("blur", function() {
949
yHint.set("innerHTML", "");
954
</script></pre>
960
<div class="yui3-u-1-4">
961
<div class="sidebar">
965
<div class="sidebox">
967
<h2 class="no-toc">Examples</h2>
971
<ul class="examples">
974
<li data-description="Use the Attribute API to define, set and get attribute values.">
975
<a href="attribute-basic.html">Basic Attribute Configuration</a>
980
<li data-description="Configure attributes to be readOnly or writeOnce.">
981
<a href="attribute-rw.html">Read-Only and Write-Once Attributes</a>
986
<li data-description="How to listen for changes in attribute values.">
987
<a href="attribute-event.html">Attribute Change Events</a>
992
<li data-description="Create a basic SpeedDater class, with Attribute support.">
993
<a href="attribute-basic-speeddate.html">Attribute Based Speed Dating</a>
998
<li data-description="Refactors the basic Speed Dating example, to use attribute change events to update rendered elements, and have two instances react to another.">
999
<a href="attribute-event-speeddate.html">Attribute Event Based Speed Dating</a>
1004
<li data-description="Add custom methods to get and set attribute values and provide validation support.">
1005
<a href="attribute-getset.html">Attribute Getters, Setters and Validators</a>
1020
<script src="../assets/vendor/prettify/prettify-min.js"></script>
1021
<script>prettyPrint();</script>