5
<title>Example: Attribute Based Speed Dating</title>
6
<link rel="stylesheet" href="http://yui.yahooapis.com/3.4.0pr3/build/cssgrids/grids-min.css">
7
<link rel="stylesheet" href="../assets/css/main.css">
8
<link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css">
9
<script src="../../build/yui/yui-min.js"></script>
14
<h1>Example: Attribute Based Speed Dating</h1>
19
<div id="main" class="yui3-u">
20
<div class="content"><style type="text/css" scoped>
32
border:1px solid #000;
37
background-color:#00f;
40
-webkit-border-radius: 10px;
41
-moz-border-radius: 10px;
43
box-shadow: 3px 3px 3px #888;
44
-moz-box-shadow: 3px 3px 3px #888;
45
-webkit-box-shadow: 3px 3px 3px #888;
48
.sd-nametag .sd-hd, .sd-nametag .sd-ft {
57
border-top-right-radius: 10px;
58
border-top-left-radius: 10px;
59
-moz-border-radius-topright: 10px;
60
-moz-border-radius-topleft: 10px;
61
-webkit-border-top-right-radius: 10px;
62
-webkit-border-top-left-radius: 10px;
66
border-bottom-right-radius: 10px;
67
border-bottom-left-radius: 10px;
68
-moz-border-radius-bottomright: 10px;
69
-moz-border-radius-bottomleft: 10px;
70
-webkit-border-bottom-right-radius: 10px;
71
-webkit-border-bottom-left-radius: 10px;
75
background-color:#fff;
79
.sd-nametag .sd-bd .sd-name,
80
.sd-nametag .sd-bd .sd-personality {
83
font-family:monospace;
84
text-decoration:underline;
88
.sd-nametag .sd-bd .sd-personality.sd-max {
96
This example builds on the <a href="attribute-basic.html">"Basic Configuration" example</a>,
97
showing how you can use attribute to model objects in your application.
101
As with the basic example, it is geared towards users who want to create their own classes from
102
scratch and add attribute support. In most cases you should consider extending the
103
<a href="../base/index.html"><code>Base</code></a> class when you need attribute support, instead
104
of augmenting Attribute directly. <a href="../base/index.html"><code>Base</code></a> does the work described
105
in this example for you, in addition to making it easier for users to extend you class.
109
<div class="example">
112
<h1>Speed Dating With Attributes</h1>
115
<button type="button" class="hi">Hi I'm John</button>
116
<button type="button" class="taken" disabled="disabled">I like Jane</button>
117
<div class="shirt"></div>
121
<button type="button" disabled="disabled" class="hi">Hey, I'm Jane</button>
122
<button type="button" class="upgrade" disabled="disabled">No way!, I save whales too!</button>
123
<button type="button" class="taken" disabled="disabled">I like John</button>
124
<div class="shirt"></div>
128
<script type="text/javascript">
130
// Get a new instance of YUI and
131
// load it with the required set of modules
133
YUI().use("node", "attribute", "substitute", function(Y) {
135
// Setup custom class which we want to
136
// add managed attribute support to
138
function SpeedDater(cfg) {
140
// When constructed, setup the initial attributes for the
141
// instance, by calling the addAttrs method.
144
// Add 3 attributes: name, personality, available
158
this.addAttrs(attrs, cfg);
161
// Setup static property to hold attribute config
163
SpeedDater.NAMETAG = '<div class="sd-nametag"><div class="sd-hd">Hello!</div><div class="sd-bd">I\'m <span class="sd-name">{name}</span> and my PersonalityQuotientIndex is <span class="sd-personality">{personality}</span></div><div class="sd-ft sd-availability">{available}</div></div>';
165
SpeedDater.prototype.applyNameTag = function(where) {
168
name: this.get("name"),
169
available: (this.get("available")) ? "I'm still looking " : "Sorry, I'm taken",
170
personality: this.get("personality")
173
var str = Y.substitute(SpeedDater.NAMETAG, tokens);
174
this.nameTag = Y.Node.create(str);
175
Y.one(where).appendChild(this.nameTag);
178
SpeedDater.prototype.updateNameTag = function() {
180
var taken = (this.get("available")) ? "I'm still looking " : "Sorry, I'm taken";
181
var name = this.get("name");
182
var personality = this.get("personality");
184
this.nameTag.one(".sd-name").set("innerHTML", name);
185
this.nameTag.one(".sd-availability").set("innerHTML", taken);
187
var personalityEl = this.nameTag.one(".sd-personality");
188
personalityEl.set("innerHTML", personality);
190
if (personality > 90) {
191
personalityEl.addClass("sd-max");
195
// Augment custom class with Attribute
196
Y.augment(SpeedDater, Y.Attribute);
200
Y.on("click", function() {
204
// Set both name and personality during construction
205
john = new SpeedDater({
209
john.applyNameTag("#john .shirt");
211
Y.one("#jane .hi").set("disabled", false);
216
Y.on("click", function() {
220
// Set name during construction
221
jane = new SpeedDater({
225
// Set personality after construction
226
jane.set("personality", 82);
228
jane.applyNameTag("#jane .shirt");
230
Y.all("#jane button").set("disabled", false);
231
Y.all("#john button").set("disabled", false);
236
Y.on("click", function() {
238
john.set("available", false);
239
john.updateNameTag();
243
Y.on("click", function() {
245
jane.set("available", false);
246
jane.updateNameTag();
250
Y.on("click", function() {
252
jane.set("personality", 98);
253
jane.updateNameTag();
255
}, "#jane .upgrade");
262
<h2>Setting Up a SpeedDater Class</h2>
264
<p>In this example, we'll create a custom <code>SpeedDater</code> class, and show how you can use attributes to manage the state for a Speed Dater.
265
In the <a href="attribute-event-speeddate.html">"Attribute Event Based Speed Dating" example</a> we'll modify this example to leverage attribute change events.</p>
267
<h3>Creating A YUI Instance</h3>
269
<p>As with the other attribute <a href="attribute-basic.html">examples</a>, we'll setup our own instance of the YUI object and request the modules we require using the code pattern shown below:</p>
271
<pre class="code prettyprint"><script type="text/javascript">
273
// Create our local YUI instance, to avoid
274
// modifying the global YUI object
276
YUI({...}).use("attribute", "node", ... function(Y) {
278
// Example code is written inside this function,
279
// which gets passed our own YUI instance, Y, populated
280
// with the modules we asked for (e.g. Y.Attribute, Y.Node etc.)
283
</script></pre>
286
<h3>Defining The SpeedDater Class</h3>
288
<p>The first step in the example is to create the constructor function for our new class, to which we want to add attribute support. In our example, this class is called <code>SpeedDater</code>.
289
We then augment <code>SpeedDater</code> with <code>Y.Attribute</code>, so that it receives all of <code>Attribute's</code> methods, in addition to any it may defined itself:</p>
291
<pre class="code prettyprint">// Setup custom class which we want to add attribute support to
292
function SpeedDater(cfg) {
296
// Augment custom class with Attribute
297
Y.augment(SpeedDater, Y.Attribute);</pre>
300
<h3>Adding Attributes</h3>
303
We can now set up any attributes we need for <code>SpeedDater</code> using Attribute's <code>addAttrs()</code> method.
305
For this example we add 3 attributes - <code>name</code>, <code>personality</code>, and <code>available</code>.
307
We provide an default initial <code>value</code> for <code>personality</code> and <code>available</code>, but don't have anything for <code>name</code>.
309
As mentioned in the basic example, the same object literal we use to provide the initial value for the attribute can also be used to configure attribute properties such as <code>readOnly</code> or
310
<code>writeOnce</code>, and to define <code>getter</code>, <code>setter</code> and <code>validator</code> methods for the attribute. For <code>name</code>, we configure it to be <code>writeOnce</code>,
311
meaning that it's value can be set once by the user, but not modified after that single set.
315
The default set of attributes which <code>SpeedDater</code> will support is passed to <code>addAttrs</code> to set up the attributes for each instance during construction.
319
As mentioned previously, if you expect your class to be extended, <a href="../base/index.html">Base</a> provides a more convenient way for you to define the same attribute configuration statically for your class, so that it can be modified by extended classes.
320
Base will take care of isolating the static configuration, so that it isn't modified across instances.
323
The complete definition for <code>SpeedDater</code> is shown below:</p>
325
<pre class="code prettyprint">// Setup custom class which we want to
326
// add managed attribute support to
328
function SpeedDater(cfg) {
330
// When constructed, setup the initial attributes for the
331
// instance, by calling the addAttrs method.
334
// Add 3 attributes: name, personality, available
348
this.addAttrs(attrs, cfg);
351
SpeedDater.prototype.applyNameTag = function(where) {
352
// Method used to render the visual representation of a
353
// SpeedDater object's state (in this case as a name tag)
356
SpeedDater.prototype.updateNameTag = function() {
357
// Method used to update the rendered state of SpeedDater in the DOM.
360
// Template to use form the markup
361
SpeedDater.NAMETAG = "<div class="sd-nametag"><div class="sd-hd">Hello!</div>... </div>";
363
// Augment custom class with Attribute
364
Y.augment(SpeedDater, Y.Attribute);</pre>
368
The <code>addAttrs()</code> method, in addition to the default attribute configuration, also accepts an object literal (associative array) of name/value pairs which can be
369
used to over-ride the default initial values of the attributes. This is useful for classes which wish to allow the user the set the value of attributes as part of object
370
construction, as shown by the use of the <code>cfg</code> argument above.
373
<h3>Using Attributes</h3>
375
<p>Now that we have <code>SpeedDater</code> defined with the set of attributes it supports, we can create multiple instances of <code>SpeedDater</code> defining the initial
376
attribute state for each instance through the constructor. We can also update the instance's attribute state after construction, using the <code>get</code> and
377
<code>set</code> methods defined by Attribute.</p>
379
<p>We create a first instance, <code>john</code>, setting up the intial state using Attribute's constructor configuration object support:</p>
381
<pre class="code prettyprint">// Set both name and personality during construction
382
john = new SpeedDater({
383
name: "John",
388
<p>For the second instance that we create, <code>jane</code>, we set the value of the personality attribute, after construction:</p>
390
<pre class="code prettyprint">// Set name during construction
391
jane = new SpeedDater({
392
name: "Jane"
395
// Set personality after construction. The initial value for personality
396
// in this case, will be the value defined when the attribute was added
397
// using addAttrs (above)
398
jane.set("personality", 82);</pre>
401
<p>We render the current attribute state of each instance to the DOM, using the <code>applyNameTag()</code> method defined on SpeedDater's prototype:</p>
403
<pre class="code prettyprint">// Render the sticker with john's state information to the DOM
404
john.applyNameTag("#john .shirt");
406
// Render the sticker with jane's state information to the DOM
407
jane.applySicker("#jane .shirt");</pre>
410
<p>Although not directly related to working with Attributes, it's worth taking a look at the <code>applyNameTag()</code> and <code>updateNameTag()</code> implementations, since they establish
411
a commonly used pattern.</p>
413
<p>The <code>applyNameTag()</code> method handles rendering the initial visual representation for a speed dater object's state (in this case a name tag). It uses tokens in an HTML "template" string, which it replaces with the values
414
of attributes using the <code>substitute()</code> utility method:</p>
416
<pre class="code prettyprint">// A template for the markup representing the SpeedDater object..
417
SpeedDater.NAMETAG = '<div class="sd-nametag"> \
418
<div class="sd-hd">Hello!</div> \
419
<div class="sd-bd">I\'m <span class="sd-name">{name}</span> \
420
and my PersonalityQuotientIndex is \
421
<span class="sd-personality">{personality}</span> \
423
<div class="sd-ft sd-availability">{available}</div> \
424
</div>';</pre>
427
<pre class="code prettyprint">// A rendering method, used to create the initial markup for the SpeedDater.
428
SpeedDater.prototype.applyNameTag = function(where) {
430
// This example uses an HTML template string containing placeholder
431
// tokens (SpeedDater.NAMETAG above), and Y.substitute to replace the
432
// tokens with the current attribute values.
435
// Get attribute values and map them to the tokens in the HTML template string
436
name: this.get("name"),
437
available: (this.get("available")) ? "I'm still looking " : "Sorry, I'm taken",
438
personality: this.get("personality")
441
// Create a new Node element, from the token substituted string...
442
this.nameTag = Y.Node.create(Y.substitute(SpeedDater.NAMETAG, tokens));
444
// ... and append it to the DOM
445
Y.one(where).appendChild(this.nameTag);
449
<p>The <code>updateNameTag()</code> method handles updating this visual representation with the current state, when requested by the user</p>
451
<pre class="code prettyprint">// An update method, used to refresh the rendered content, after
452
// an attribute value is changed.
453
SpeedDater.prototype.updateNameTag = function() {
455
// Get current attribute values...
456
var taken = (this.get("available")) ? "I'm still looking " : "Sorry, I'm taken";
457
var name = this.get("name");
458
var personality = this.get("personality");
460
// Find the corresponding element, and replace the innerHTML with the new value
461
this.nameTag.one(".sd-name").set("innerHTML", name);
462
this.nameTag.one(".sd-availability").set("innerHTML", taken);
464
var personalityEl = this.nameTag.one(".sd-personality");
465
personalityEl.set("innerHTML", personality);
467
if (personality > 90) {
468
personalityEl.addClass("sd-max");
473
<p>Each instance's state can be now be updated using Attribute's <code>set</code> method, and the subsequent call to SpeedDater's <code>updateNameTag()</code> method will update the visual representation (the rendered DOM) of the object:</p>
475
<pre class="code prettyprint">Y.on("click", function() {
477
john.set("available", false);
478
john.updateNameTag();
480
}, "#john .taken");
482
Y.on("click", function() {
484
jane.set("available", false);
485
jane.updateNameTag();
487
}, "#jane .taken");
489
Y.on("click", function() {
491
jane.set("personality", 98);
492
jane.updateNameTag();
494
}, "#jane .upgrade");</pre>
497
<p>In the <a href="attribute-event-speeddate.html">"Attribute Event Based Speed Dating" example</a>, we'll see how we can use Attribute change events to eliminate the need for users to call <code>updateNameTag()</code> each time they set an attribute, and have the two instances communicate with one another.</p>
499
<h2>Complete Example Source</h2>
501
<pre class="code prettyprint"><div id="speeddate">
503
<h1>Speed Dating With Attributes</h1>
505
<div id="john">
506
<button type="button" class="hi">Hi I'm John</button>
507
<button type="button" class="taken" disabled="disabled">I like Jane</button>
508
<div class="shirt"></div>
511
<div id="jane">
512
<button type="button" disabled="disabled" class="hi">Hey, I'm Jane</button>
513
<button type="button" class="upgrade" disabled="disabled">No way!, I save whales too!</button>
514
<button type="button" class="taken" disabled="disabled">I like John</button>
515
<div class="shirt"></div>
519
<script type="text/javascript">
521
// Get a new instance of YUI and
522
// load it with the required set of modules
524
YUI().use("node", "attribute", "substitute", function(Y) {
526
// Setup custom class which we want to
527
// add managed attribute support to
529
function SpeedDater(cfg) {
531
// When constructed, setup the initial attributes for the
532
// instance, by calling the addAttrs method.
535
// Add 3 attributes: name, personality, available
549
this.addAttrs(attrs, cfg);
552
// Setup static property to hold attribute config
554
SpeedDater.NAMETAG = '<div class="sd-nametag"><div class="sd-hd">Hello!</div><div class="sd-bd">I\'m <span class="sd-name">{name}</span> and my PersonalityQuotientIndex is <span class="sd-personality">{personality}</span></div><div class="sd-ft sd-availability">{available}</div></div>';
556
SpeedDater.prototype.applyNameTag = function(where) {
559
name: this.get("name"),
560
available: (this.get("available")) ? "I'm still looking " : "Sorry, I'm taken",
561
personality: this.get("personality")
564
var str = Y.substitute(SpeedDater.NAMETAG, tokens);
565
this.nameTag = Y.Node.create(str);
566
Y.one(where).appendChild(this.nameTag);
569
SpeedDater.prototype.updateNameTag = function() {
571
var taken = (this.get("available")) ? "I'm still looking " : "Sorry, I'm taken";
572
var name = this.get("name");
573
var personality = this.get("personality");
575
this.nameTag.one(".sd-name").set("innerHTML", name);
576
this.nameTag.one(".sd-availability").set("innerHTML", taken);
578
var personalityEl = this.nameTag.one(".sd-personality");
579
personalityEl.set("innerHTML", personality);
581
if (personality > 90) {
582
personalityEl.addClass("sd-max");
586
// Augment custom class with Attribute
587
Y.augment(SpeedDater, Y.Attribute);
591
Y.on("click", function() {
595
// Set both name and personality during construction
596
john = new SpeedDater({
597
name: "John",
600
john.applyNameTag("#john .shirt");
602
Y.one("#jane .hi").set("disabled", false);
605
}, "#john .hi");
607
Y.on("click", function() {
611
// Set name during construction
612
jane = new SpeedDater({
613
name: "Jane"
616
// Set personality after construction
617
jane.set("personality", 82);
619
jane.applyNameTag("#jane .shirt");
621
Y.all("#jane button").set("disabled", false);
622
Y.all("#john button").set("disabled", false);
625
}, "#jane .hi");
627
Y.on("click", function() {
629
john.set("available", false);
630
john.updateNameTag();
632
}, "#john .taken");
634
Y.on("click", function() {
636
jane.set("available", false);
637
jane.updateNameTag();
639
}, "#jane .taken");
641
Y.on("click", function() {
643
jane.set("personality", 98);
644
jane.updateNameTag();
646
}, "#jane .upgrade");
649
</script></pre>
654
<div id="sidebar" class="yui3-u">
658
<div class="sidebox">
660
<h2 class="no-toc">Examples</h2>
664
<ul class="examples">
667
<li data-description="Use the Attribute API to define, set and get attribute values.">
668
<a href="attribute-basic.html">Basic Attribute Configuration</a>
673
<li data-description="Configure attributes to be readOnly or writeOnce.">
674
<a href="attribute-rw.html">Read-Only and Write-Once Attributes</a>
679
<li data-description="How to listen for changes in attribute values.">
680
<a href="attribute-event.html">Attribute Change Events</a>
685
<li data-description="Create a basic SpeedDater class, with Attribute support.">
686
<a href="attribute-basic-speeddate.html">Attribute Based Speed Dating</a>
691
<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.">
692
<a href="attribute-event-speeddate.html">Attribute Event Based Speed Dating</a>
697
<li data-description="Add custom methods to get and set attribute values and provide validation support.">
698
<a href="attribute-getset.html">Attribute Getters, Setters and Validators</a>
712
<script src="../assets/vendor/prettify/prettify-min.js"></script>
713
<script>prettyPrint();</script>