A demonstration of the DataTable's row expansion feature to display a list of "Interestingness" from Flickr. When the table first loads, it displays a list of image titles. When a row is expanded the photo is displayed in the expansion area along with a link to the Flickr user's photostream. A simple string-based template is used to format the row expansion area.
This example is designed to assume that expanded rows will be wiped out and restored when the DataTable paginates or sorts, which is why we keep track of expanded rows and automatically restore them after each rendering of the DataTable. Anytime the restoreExpandedRows
method is called and the state shows a row is open, its expansion will be re-created.
Interestingness | |
---|---|
Loading... |
1 | /** |
2 | * |
3 | * Style the yui-dt-expandablerow-trigger column |
4 | * |
5 | **/ |
6 | .yui-dt-expandablerow-trigger{ |
7 | width:18px; |
8 | height:22px; |
9 | cursor:pointer; |
10 | } |
11 | .yui-dt-expanded .yui-dt-expandablerow-trigger{ |
12 | background:url(arrow_open.png) 4px 4px no-repeat; |
13 | } |
14 | .yui-dt-expandablerow-trigger, .yui-dt-collapsed .yui-dt-expandablerow-trigger{ |
15 | background:url(arrow_closed.png) 4px 4px no-repeat; |
16 | } |
17 | .yui-dt-expanded .yui-dt-expandablerow-trigger.spinner{ |
18 | background:url(spinner.gif) 1px 4px no-repeat; |
19 | } |
20 | |
21 | /** |
22 | * |
23 | * Style the expansion row |
24 | * |
25 | **/ |
26 | .yui-dt-expansion .yui-dt-liner{ |
27 | padding:0; |
28 | border:solid 0 #bbb; |
29 | border-width: 0 0 2px 0; |
30 | } |
31 | .yui-dt-expansion .yui-dt-liner th, .yui-dt-expansion .yui-dt-liner table{ |
32 | border:none; |
33 | background-color:#fff; |
34 | } |
35 | .yui-dt-expansion .yui-dt-liner th, .yui-dt-expansion .yui-dt-liner table th{ |
36 | background-image:none; |
37 | background-color:#eee; |
38 | } |
39 | .yui-dt-expansion .yui-dt-liner th, .yui-dt-expansion .yui-dt-liner table td{ |
40 | border:solid 0 #eee; |
41 | border-width: 0 0 1px 1px; |
42 | } |
43 | .yui-dt-expansion .yui-dt-liner th, .yui-dt-expansion .yui-dt-liner table td div{ |
44 | padding:3px; |
45 | overflow:hidden; |
46 | width:100px; |
47 | } |
48 | .yui-dt-expansion .yui-dt-liner th, .yui-dt-expansion .yui-dt-liner table td.big div{ |
49 | width:300px; |
50 | } |
51 | .yui-dt-expansion .yui-dt-liner th, .yui-dt-expansion .yui-dt-liner table td ul{ padding:0;margin:0; } |
view plain | print | ? |
Also available here.
1 | /* This code should not be modified */ |
2 | (function(){ |
3 | |
4 | var Dom = YAHOO.util.Dom |
5 | |
6 | STRING_STATENAME = 'yui_dt_state', |
7 | |
8 | CLASS_EXPANDED = 'yui-dt-expanded', |
9 | CLASS_COLLAPSED = 'yui-dt-collapsed', |
10 | CLASS_EXPANSION = 'yui-dt-expansion', |
11 | CLASS_LINER = 'yui-dt-liner', |
12 | |
13 | //From YUI 3 |
14 | indexOf = function(a, val) { |
15 | for (var i=0; i<a.length; i=i+1) { |
16 | if (a[i] === val) { |
17 | return i; |
18 | } |
19 | } |
20 | |
21 | return -1; |
22 | }; |
23 | |
24 | /** |
25 | * The RowExpansionDataTable class extends the DataTable class to provide |
26 | * functionality for expanding rows to show more contextual data. |
27 | * |
28 | * @namespace YAHOO.widget |
29 | * @class RowExpansionDataTable |
30 | * @extends YAHOO.widget.DataTable |
31 | * @constructor |
32 | * @param elContainer {HTMLElement} Container element for the TABLE. |
33 | * @param aColumnDefs {Object[]} Array of object literal Column definitions. |
34 | * @param oDataSource {YAHOO.util.DataSource} DataSource instance. |
35 | * @param oConfigs {object} (optional) Object literal of configuration values. |
36 | */ |
37 | YAHOO.widget.RowExpansionDataTable = function(elContainer,aColumnDefs,oDataSource,oConfigs) { |
38 | oConfigs = oConfigs || {}; |
39 | |
40 | YAHOO.widget.RowExpansionDataTable.superclass.constructor.call(this, elContainer,aColumnDefs,oDataSource,oConfigs); |
41 | |
42 | }; |
43 | |
44 | YAHOO.lang.extend( |
45 | YAHOO.widget.RowExpansionDataTable, |
46 | YAHOO.widget.DataTable, |
47 | { |
48 | |
49 | ////////////////////////////////////////////////////////////////// |
50 | // |
51 | // Private members |
52 | // |
53 | ////////////////////////////////////////////////////////////////// |
54 | |
55 | /** |
56 | * Gets state object for a specific record associated with the |
57 | * DataTable. |
58 | * |
59 | * @method _getRecordState |
60 | * @param {Mixed} record_id Record / Row / or Index id |
61 | * @param {String} key Key to return within the state object. Default is to |
62 | * return all as a map |
63 | * @return {Object} State data object |
64 | * @protected |
65 | **/ |
66 | _getRecordState : function( record_id, key ){ |
67 | |
68 | var row_data = this.getRecord( record_id ), |
69 | row_state = row_data.getData( STRING_STATENAME ), |
70 | state_data = ( row_state && key ) ? row_state[ key ] : row_state; |
71 | |
72 | return state_data || {}; |
73 | |
74 | }, |
75 | |
76 | /** |
77 | * Sets a value to a state object with a unique id for a record |
78 | * which is associated with the DataTable |
79 | * |
80 | * @method _setRecordState |
81 | * @param {Mixed} record_id Record / Row / or Index id |
82 | * @param {String} key Key to use in map |
83 | * @param {Mixed} value Value to assign to the key |
84 | * @return {Object} State data object |
85 | * @protected |
86 | **/ |
87 | _setRecordState : function( record_id, key, value ){ |
88 | |
89 | var row_data = this.getRecord( record_id ).getData(), |
90 | merged_data = row_data[ STRING_STATENAME ] || {}; |
91 | |
92 | merged_data[ key ] = value; |
93 | |
94 | this.getRecord( record_id ).setData( STRING_STATENAME, merged_data ); |
95 | |
96 | return merged_data; |
97 | |
98 | }, |
99 | |
100 | ////////////////////////////////////////////////////////////////// |
101 | // |
102 | // Public methods |
103 | // |
104 | ////////////////////////////////////////////////////////////////// |
105 | |
106 | /** |
107 | * Over-ridden initAttributes method from DataTable |
108 | * |
109 | * @method initAttributes |
110 | * @param {Mixed} record_id Record / Row / or Index id |
111 | * @param {String} key Key to use in map |
112 | * @param {Mixed} value Value to assign to the key |
113 | * @return {Object} State data object |
114 | **/ |
115 | initAttributes : function( oConfigs ) { |
116 | |
117 | oConfigs = oConfigs || {}; |
118 | |
119 | YAHOO.widget.RowExpansionDataTable.superclass.initAttributes.call( this, oConfigs ); |
120 | |
121 | /** |
122 | * Value for the rowExpansionTemplate attribute. |
123 | * |
124 | * @attribute rowExpansionTemplate |
125 | * @type {Mixed} |
126 | * @default "" |
127 | **/ |
128 | this.setAttributeConfig("rowExpansionTemplate", { |
129 | value: "", |
130 | validator: function( template ){ |
131 | return ( |
132 | YAHOO.lang.isString( template ) || |
133 | YAHOO.lang.isFunction( template ) |
134 | ); |
135 | }, |
136 | method: this.initRowExpansion |
137 | }); |
138 | |
139 | }, |
140 | |
141 | /** |
142 | * Initializes row expansion on the DataTable instance |
143 | * |
144 | * @method initRowExpansion |
145 | * @param {Mixed} template a string template or function to be |
146 | * called when Row is expanded |
147 | **/ |
148 | initRowExpansion : function( template ){ |
149 | |
150 | //Set subscribe restore method |
151 | this.subscribe( 'postRenderEvent', this.onEventRestoreRowExpansion ); |
152 | |
153 | //Setup template |
154 | this.rowExpansionTemplate = template; |
155 | |
156 | //Set table level state |
157 | this.a_rowExpansions = []; |
158 | |
159 | }, |
160 | |
161 | /** |
162 | * Toggles the expansion state of a row |
163 | * |
164 | * @method toggleRowExpansion |
165 | * @param {Mixed} record_id Record / Row / or Index id |
166 | **/ |
167 | toggleRowExpansion : function( record_id ){ |
168 | |
169 | var state = this._getRecordState( record_id ); |
170 | |
171 | if( state && state.expanded ){ |
172 | |
173 | this.collapseRow( record_id ); |
174 | |
175 | } else { |
176 | |
177 | this.expandRow( record_id ); |
178 | |
179 | } |
180 | |
181 | }, |
182 | |
183 | /** |
184 | * Sets the expansion state of a row to expanded |
185 | * |
186 | * @method expandRow |
187 | * @param {Mixed} record_id Record / Row / or Index id |
188 | * @param {Boolean} restore will restore an exisiting state for a |
189 | * row that has been collapsed by a non user action |
190 | * @return {Boolean} successful |
191 | **/ |
192 | expandRow : function( record_id, restore ){ |
193 | |
194 | var state = this._getRecordState( record_id ); |
195 | |
196 | if( !state.expanded || restore ){ |
197 | |
198 | var row_data = this.getRecord( record_id ), |
199 | row = this.getRow( row_data ), |
200 | new_row = document.createElement('tr'), |
201 | column_length = this.getFirstTrEl().childNodes.length, |
202 | expanded_data = row_data.getData(), |
203 | expanded_content = null, |
204 | template = this.rowExpansionTemplate, |
205 | next_sibling = Dom.getNextSibling( row ); |
206 | |
207 | //Construct expanded row body |
208 | new_row.className = CLASS_EXPANSION; |
209 | var new_column = document.createElement( 'td' ); |
210 | new_column.colSpan = column_length; |
211 | |
212 | new_column.innerHTML = '<div class="'+ CLASS_LINER +'"></div>'; |
213 | new_row.appendChild( new_column ); |
214 | |
215 | var liner_element = new_row.firstChild.firstChild; |
216 | |
217 | if( YAHOO.lang.isString( template ) ){ |
218 | |
219 | liner_element.innerHTML = YAHOO.lang.substitute( |
220 | template, |
221 | expanded_data |
222 | ); |
223 | |
224 | } else if( YAHOO.lang.isFunction( template ) ) { |
225 | |
226 | template( { |
227 | row_element : new_row, |
228 | liner_element : liner_element, |
229 | data : row_data, |
230 | state : state |
231 | } ); |
232 | |
233 | } else { |
234 | |
235 | return false; |
236 | |
237 | } |
238 | |
239 | //Insert new row |
240 | newRow = Dom.insertAfter( new_row, row ); |
241 | |
242 | if (newRow.innerHTML.length) { |
243 | |
244 | this._setRecordState( record_id, 'expanded', true ); |
245 | |
246 | if( !restore ){ |
247 | |
248 | this.a_rowExpansions.push( this.getRecord( record_id ).getId() ); |
249 | |
250 | } |
251 | |
252 | Dom.removeClass( row, CLASS_COLLAPSED ); |
253 | Dom.addClass( row, CLASS_EXPANDED ); |
254 | |
255 | //Fire custom event |
256 | this.fireEvent( "rowExpandEvent", { record_id : row_data.getId() } ); |
257 | |
258 | return true; |
259 | |
260 | } else { |
261 | |
262 | return false; |
263 | |
264 | } |
265 | |
266 | } |
267 | |
268 | }, |
269 | |
270 | /** |
271 | * Sets the expansion state of a row to collapsed |
272 | * @method collapseRow |
273 | * @param {Mixed} record_id Record / Row / or Index id |
274 | * @return {Boolean} successful |
275 | **/ |
276 | collapseRow : function( record_id ){ |
277 | |
278 | var row_data = this.getRecord( record_id ), |
279 | row = Dom.get( row_data.getId() ), |
280 | state = row_data.getData( STRING_STATENAME ); |
281 | |
282 | if( state && state.expanded ){ |
283 | |
284 | var next_sibling = Dom.getNextSibling( row ), |
285 | hash_index = indexOf( this.a_rowExpansions, record_id ); |
286 | |
287 | if( Dom.hasClass( next_sibling, CLASS_EXPANSION ) ) { |
288 | |
289 | next_sibling.parentNode.removeChild( next_sibling ); |
290 | this.a_rowExpansions.splice( hash_index, 1 ); |
291 | this._setRecordState( record_id, 'expanded', false ); |
292 | |
293 | Dom.addClass( row, CLASS_COLLAPSED ); |
294 | Dom.removeClass( row, CLASS_EXPANDED ); |
295 | |
296 | //Fire custom event |
297 | this.fireEvent("rowCollapseEvent", { record_id : row_data.getId() } ); |
298 | |
299 | return true; |
300 | |
301 | } else { |
302 | |
303 | return false; |
304 | |
305 | } |
306 | |
307 | } |
308 | |
309 | }, |
310 | |
311 | /** |
312 | * Collapses all expanded rows. This should be called before any |
313 | * action where the row expansion markup would interfear with |
314 | * normal DataTable markup handling. This method does not remove |
315 | * exents attached during implementation. All event handlers should |
316 | * be removed separately. |
317 | * |
318 | * @method collapseAllRows |
319 | **/ |
320 | collapseAllRows : function(){ |
321 | |
322 | var rows = this.a_rowExpansions; |
323 | |
324 | for( var i = 0, l = rows.length; l > i; i++ ){ |
325 | |
326 | //Always pass 0 since collapseRow removes item from the a_rowExpansions array |
327 | this.collapseRow( rows[ 0 ] ); |
328 | |
329 | } |
330 | |
331 | a_rowExpansions = []; |
332 | |
333 | }, |
334 | |
335 | /** |
336 | * Restores rows which have an expanded state but no markup. This |
337 | * is to be called to restore row expansions after the DataTable |
338 | * renders or the collapseAllRows is called. |
339 | * |
340 | * @method collapseAllRows |
341 | **/ |
342 | restoreExpandedRows : function(){ |
343 | |
344 | var expanded_rows = this.a_rowExpansions; |
345 | |
346 | if( !expanded_rows.length ){ |
347 | |
348 | return; |
349 | |
350 | } |
351 | |
352 | if( this.a_rowExpansions.length ){ |
353 | |
354 | for( var i = 0, l = expanded_rows.length; l > i; i++ ){ |
355 | |
356 | this.expandRow( expanded_rows[ i ] , true ); |
357 | |
358 | } |
359 | |
360 | } |
361 | |
362 | }, |
363 | |
364 | /** |
365 | * Abstract method which restores row expansion for subscribing to |
366 | * the DataTable postRenderEvent. |
367 | * |
368 | * @method onEventRestoreRowExpansion |
369 | * @param {Object} oArgs context of a subscribed event |
370 | **/ |
371 | onEventRestoreRowExpansion : function( oArgs ){ |
372 | |
373 | this.restoreExpandedRows(); |
374 | |
375 | }, |
376 | |
377 | /** |
378 | * Abstract method which toggles row expansion for subscribing to |
379 | * the DataTable postRenderEvent. |
380 | * |
381 | * @method onEventToggleRowExpansion |
382 | * @param {Object} oArgs context of a subscribed event |
383 | **/ |
384 | onEventToggleRowExpansion : function( oArgs ){ |
385 | |
386 | if( YAHOO.util.Dom.hasClass( oArgs.target, 'yui-dt-expandablerow-trigger' ) ){ |
387 | |
388 | this.toggleRowExpansion( oArgs.target ); |
389 | |
390 | } |
391 | |
392 | } |
393 | |
394 | }); |
395 | |
396 | })(); |
view plain | print | ? |
1 | /* Modify as needed */ |
2 | |
3 | YAHOO.util.Event.onDOMReady( function() { |
4 | YAHOO.example.Basic = function() { |
5 | var expansionFormatter = function(el, oRecord, oColumn, oData) { |
6 | var cell_element = el.parentNode; |
7 | |
8 | //Set trigger |
9 | if( oData ){ //Row is closed |
10 | YAHOO.util.Dom.addClass( cell_element, |
11 | "yui-dt-expandablerow-trigger" ); |
12 | } |
13 | |
14 | }; |
15 | |
16 | var myDataSource = new |
17 | YAHOO.util.DataSource(YAHOO.example.interestingness); |
18 | myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSARRAY; |
19 | myDataSource.responseSchema = { |
20 | fields: ["title","farm","server","id","secret","owner"] |
21 | }; |
22 | |
23 | var myDataTable = new YAHOO.widget.RowExpansionDataTable( |
24 | "event_table", |
25 | [ |
26 | { |
27 | key:"farm", |
28 | label:"", |
29 | formatter:expansionFormatter |
30 | }, |
31 | { |
32 | key:"title", |
33 | label:"Interestingness", |
34 | width : '200px', |
35 | sortable:true |
36 | } |
37 | ], |
38 | myDataSource, |
39 | { rowExpansionTemplate : |
40 | '<img src="http://farm{farm}.static.flickr.com/'+ |
41 | '{server}/{id}_{secret}_m_d.jpg" />' } |
42 | ); |
43 | |
44 | //Subscribe to a click event to bind to |
45 | myDataTable.subscribe( 'cellClickEvent', |
46 | myDataTable.onEventToggleRowExpansion ); |
47 | |
48 | return { |
49 | oDS: myDataSource, |
50 | oDT: myDataTable |
51 | }; |
52 | }(); |
53 | }); |
view plain | print | ? |
You can load the necessary JavaScript and CSS for this example from Yahoo's servers. Click here to load the YUI Dependency Configurator with all of this example's dependencies preconfigured.
Note: Logging and debugging is currently turned off for this example.
Copyright © 2010 Yahoo! Inc. All rights reserved.
Privacy Policy - Terms of Service - Copyright Policy - Job Openings