diff -r 322d0feea350 -r 89ef5ed3c48b src/cm/media/js/lib/yui/yui_3.10.3/docs/datatable/datatable-masterdetail.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cm/media/js/lib/yui/yui_3.10.3/docs/datatable/datatable-masterdetail.html Tue Jul 16 14:29:46 2013 +0200 @@ -0,0 +1,655 @@ + + + + + Example: Master and detail tables + + + + + + + + + + +
+
+

+
+ + +

Example: Master and detail tables

+
+
+
+
+ +
+

Demonstrates a method of linking two DataTables together. In this case we link a row selection within a Master (or "parent") table + to creation of a separate Detail (or "child") table. This is a common usage case for datasets that may have related rows within + different datasets or as a result of typical database one-to-many key relationships. +

+
+ +
+
+ + + +
+ + +

Sample Data

+ +

Let's assume we have an array of data that includes parent elements and children elements. The example we'll use defines several animal +categories and for each category it provides the names of some common characters from literature or pop culture of each type (except for the lowly +amoeba, we couldn't think of any ...).

+
var animal_data = [
+    {  aname: 'Lions',  chars:[ 'Leo', 'Simba', 'Elsa', 'Cowardly Lion' ] },
+    {  aname: 'Amoebas' },
+    {  aname: 'Tigers', chars:[ 'Shere Kahn', 'Tigger', 'Tony' ] },
+    {  aname: 'Mules',  chars:[ 'Francis' ] },
+    {  aname: 'Bears',  chars:[ 'Smokey', 'Reginald', 'Winnie-the-Pooh', 'Baloo', 'Yogi' ] },
+    {  aname: 'Snakes', chars:[ 'Kaa', 'The Serpent', 'Nagini' ] }
+];
+ + +

The DataTables

+ +

Two DataTables are utilized for this example and for convenience they operate using the same animal_data JavaScript array. In most practical applications +the data would probably be received from a remote source via DataSource or using the Model sync capability. +

+ +

The "Master" table

+ +

Our primary DataTable consists of two columns, aname which is the category of the animals and the other column is +a calculated (or "unbound") column that is populated by a custom formatter. The custom formatter for nchars simply returns the length of the chars array +associated with the record, or zero if none are defined.

+ +
var dt_master = new Y.DataTable({
+    columns : [
+        { key:'aname',  label:'Type' },
+        { name:'nchars', label:'No. of Chars',
+          formatter: function(o){
+               return ( o.data.chars ) ? o.data.chars.length : 0;
+             }
+        }
+    ],
+    data : animal_data,
+    width: 200,
+    caption: 'Select an animal category below:'
+}).render("#mtable");
+ + +

Since we will need a click handler to track TR clicks on the Master DataTable, we will define a new +attribute selectedRow and setup a TR click handler that assigns this attribute on a click.

+ +
//
+// Add a new attribute to track the last TR clicked,
+//   this is used in the details DT formatter below and later
+//   in the row click handler `delegate` for row highlighting
+//
+//  also setup a click listener to update the "selectedRow" attribute on TR clicks
+//
+dt_master.addAttr("selectedRow", { value: null });
+
+dt_master.delegate('click', function (e) {
+    this.set('selectedRow', e.currentTarget);
+ }, '.yui3-datatable-data tr', dt_master);
+ + +

The "Detail" table

+ +

We can proceed with defining the linked child table and rendering it initially because we have hidden +this DataTable within a DIV with style display:none; (the DIV becomes visible on the first row click). This child DataTable consisits of +another calculated (i.e. unbound) column aname (which just fills with the parent category name) and + a column char_name. The data for this table is initially empty, but will be populated by the click handler.

+ +
var dt_detail = new Y.DataTable({
+    columns : [
+        { name:'aname', label:'Animal Category',
+          formatter: function(o){
+                // just retrieve the selected Master record and return the "aname" column
+                var parent_rec = dt_master.getRecord( dt_master.get('selectedRow') );
+                return parent_rec.get('aname');
+            }
+        },
+        { key:'char_name', label:'Character' }
+     ],
+    data : [],
+    strings : {
+        emptyMessage : "No critter characters were found!"
+    },
+    width: 350,
+    caption: 'Characters of the category include:'
+}).render("#dtable");
+ + +

The selectedRow Listener

+

+ The "glue" between the master and detail DataTables is the delegated click handler on + the Master DataTable's rows -- or more specifically, the selectedRowChange event handler. When a row is clicked and the + selectedRow is changed, the underlying record from the Master table is + determined and the Detail DataTable is populated with the corresponding chars data from the clicked record. + We also handle TR highlighting for the clicked row by toggling a background color within this delegate handler. +

+
dt_master.after('selectedRowChange', function (e) {
+
+    var tr = e.newVal,              // the Node for the TR clicked ...
+        last_tr = e.prevVal,        //  "   "   "   the last TR clicked ...
+        rec = this.getRecord(tr);   // the current Record for the clicked TR
+
+    //
+    //  This if-block does double duty,
+    //  (a) it tracks the first click to toggle the "details" DIV to visible
+    //  (b) it un-hightlights the last TR clicked
+    //
+    if ( !last_tr ) {
+        // first time thru ... display the Detail DT DIV that was hidden
+        Y.one("#chars").show();
+    } else {
+        last_tr.removeClass("myhilite");
+    }
+
+    //
+    //  After unhighlighting, now highlight the current TR
+    //
+    tr.addClass("myhilite");
+
+
+    //
+    //  Collect the "chars" member of the parent record into an array of
+    //  objects  with property name "aname"
+    //
+    var detail_data = [];
+    if ( rec.get('chars') ) {
+        Y.Array.each( rec.get('chars'), function(item){
+            detail_data.push( {char_name:item});
+        });
+    }
+
+    //
+    //  Set the "detail_data" to the dt_detail DataTable
+    //    also update the heading in "acategory"
+    //   ( it automatically refreshes )
+    //
+    dt_detail.setAttrs({
+        data: detail_data,
+        caption: 'Characters of the <strong>' + rec.get('aname') +
+                    '</strong> category include:'
+    });
+});
+ + +

+ Note: In the case of the use of remote data via DataSource, the + selectedRowChange handler could be modified to generate a sendRequest + or similar remote call for the Detail data and the on:success handler + could be setup to set the data attribute. +

+ +

Full Source Code

+ +

CSS

+
.yui3-skin-sam .yui3-datatable-caption {
+    font-size: 13px;
+    font-style: normal;
+    text-align: left;
+}
+
+.yui3-datatable-col-nchars {
+    text-align: center;
+}
+
+.yui3-skin-sam .yui3-datatable tr.myhilite td {
+    background-color: #C0ffc0;
+}
+
+#mtable tbody tr {      /*  Turn on cursor to show TR's are selectable on Master DataTable only  */
+    cursor: pointer;
+}
+ + +

HTML Markup

+

+Note: be sure to add the yui3-skin-sam classname to the +page's <body> element or to a parent element of the widget in order to apply +the default CSS skin. See Understanding Skinning. +

+
<div id="template" class="yui3-skin-sam dt-example yui3-g"> <!-- You need this skin class -->
+    <div class="yui3-u-1-3" id="mtable"></div>
+
+    <!-- This is the HTML section for the "Details" markup ...
+         NOTE: it is hidden initially !!   -->
+    <div class="yui3-u-2-3" id="chars" style="display:none;">
+        <div id="dtable"></div>
+    </div>
+</div>
+ + +

Javascript

+
YUI().use(   "datatable", function (Y) {
+
+    var animal_data = [
+        {  aname: 'Lions',  chars:[ 'Leo', 'Simba', 'Elsa', 'Cowardly Lion' ] },
+        {  aname: 'Amoebas' },
+        {  aname: 'Tigers', chars:[ 'Shere Kahn', 'Tigger', 'Tony' ] },
+        {  aname: 'Mules',  chars:[ 'Francis' ] },
+        {  aname: 'Bears',  chars:[ 'Smokey', 'Reginald', 'Winnie-the-Pooh', 'Baloo', 'Yogi' ] },
+        {  aname: 'Snakes', chars:[ 'Kaa', 'The Serpent', 'Nagini' ] }
+    ];
+
+    //
+    //   Create the "parent" DataTable
+    //
+    var dt_master = new Y.DataTable({
+        columns : [
+            { key:'aname',  label:'Type' },
+            { name:'nchars', label:'No. of Chars',
+              formatter: function(o){
+                   return ( o.data.chars ) ? o.data.chars.length : 0;
+                 }
+            }
+        ],
+        data : animal_data,
+        width: 200,
+        caption: 'Select an animal category below:'
+    }).render("#mtable");
+
+    //
+    // Add a new attribute to track the last TR clicked,
+    //   this is used in the details DT formatter below and later
+    //   in the row click handler `delegate` for row highlighting
+    //
+    //  also setup a click listener to update the "selectedRow" attribute on TR
+    //  clicks
+    //
+    dt_master.addAttr("selectedRow", { value: null });
+
+    dt_master.delegate('click', function (e) {
+        this.set('selectedRow', e.currentTarget);
+     }, '.yui3-datatable-data tr', dt_master);
+
+    //
+    //   Create the characters DataTable and render it (it is hidden initially)
+    //
+    var dt_detail = new Y.DataTable({
+        columns : [
+            { name:'aname', label:'Animal Category',
+              formatter: function(o){
+                    // just retrieve the selected Master record and return the
+                    // "aname" column
+                    var parent_rec = dt_master.getRecord(
+                        dt_master.get('selectedRow') );
+
+                    return parent_rec.get('aname');
+                }
+            },
+            { key:'char_name', label:'Character' }
+         ],
+        data : [],
+        strings : {
+            emptyMessage : "No critter characters were found!"
+        },
+        width: 350,
+        caption: 'Characters of the category include:'
+    }).render("#dtable");
+
+    //
+    //  Setup a listener to the Master "selectedRowChange" event (i.e. after a
+    //  row click)
+    //
+    dt_master.after('selectedRowChange', function (e) {
+
+        var tr = e.newVal,              // the Node for the TR clicked ...
+            last_tr = e.prevVal,        //  "   "   "   the last TR clicked ...
+            rec = this.getRecord(tr);   // the current Record for the clicked TR
+
+        //
+        //  This if-block does double duty,
+        //  (a) it tracks the first click to toggle the "details" DIV to visible
+        //  (b) it un-hightlights the last TR clicked
+        //
+        if ( !last_tr ) {
+            // first time thru ... display the Detail DT DIV that was hidden
+            Y.one("#chars").show();
+        } else {
+            last_tr.removeClass("myhilite");
+        }
+
+        //
+        //  After unhighlighting, now highlight the current TR
+        //
+        tr.addClass("myhilite");
+
+
+        //
+        //  Collect the "chars" member of the parent record into an array of
+        //  objects  with property name "aname"
+        //
+        var detail_data = [];
+        if ( rec.get('chars') ) {
+            Y.Array.each( rec.get('chars'), function(item){
+                detail_data.push( {char_name:item});
+            });
+        }
+
+        //
+        //  Set the "detail_data" to the dt_detail DataTable
+        //    also update the heading in "acategory"
+        //   ( it automatically refreshes )
+        //
+        dt_detail.setAttrs({
+            data: detail_data,
+            caption: 'Characters of the <strong>' + rec.get('aname') +
+                        '</strong> category include:'
+        });
+    });
+
+});
+ +
+
+
+ +
+ +
+
+
+ + + + + + + + + + +