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. This example uses a simple string-based template to format the row expansion area.
Interestingness | |
---|---|
Custom CSS for this example:
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 | ? |
DataTable RowExpansion extension code:
1 | /* This code should not be modified */ |
2 | |
3 | (function(){ |
4 | |
5 | var Dom = YAHOO.util.Dom, |
6 | |
7 | STRING_STATENAME = 'yui_dt_state', |
8 | |
9 | CLASS_EXPANDED = 'yui-dt-expanded', |
10 | CLASS_COLLAPSED = 'yui-dt-collapsed', |
11 | CLASS_EXPANSION = 'yui-dt-expansion', |
12 | CLASS_LINER = 'yui-dt-liner', |
13 | |
14 | //From YUI 3 |
15 | indexOf = function(a, val) { |
16 | for (var i=0; i<a.length; i=i+1) { |
17 | if (a[i] === val) { |
18 | return i; |
19 | } |
20 | } |
21 | |
22 | return -1; |
23 | }; |
24 | |
25 | YAHOO.lang.augmentObject( |
26 | YAHOO.widget.DataTable.prototype , { |
27 | |
28 | //////////////////////////////////////////////////////////////////// |
29 | // |
30 | // Private members |
31 | // |
32 | //////////////////////////////////////////////////////////////////// |
33 | |
34 | /** |
35 | * Gets state object for a specific record associated with the |
36 | * DataTable. |
37 | * @method _getRecordState |
38 | * @param {Mixed} record_id Record / Row / or Index id |
39 | * @param {String} key Key to return within the state object. |
40 | * Default is to return all as a map |
41 | * @return {Object} State data object |
42 | * @type mixed |
43 | * @private |
44 | **/ |
45 | _getRecordState : function( record_id, key ){ |
46 | var row_data = this.getRecord( record_id ), |
47 | row_state = row_data.getData( STRING_STATENAME ), |
48 | state_data = (row_state && key) ? row_state[ key ]:row_state; |
49 | |
50 | return state_data || {}; |
51 | }, |
52 | |
53 | /** |
54 | * Sets a value to a state object with a unique id for a record |
55 | * which is associated with the DataTable |
56 | * @method _setRecordState |
57 | * @param {Mixed} record_id Record / Row / or Index id |
58 | * @param {String} key Key to use in map |
59 | * @param {Mixed} value Value to assign to the key |
60 | * @return {Object} State data object |
61 | * @type mixed |
62 | * @private |
63 | **/ |
64 | _setRecordState : function( record_id, key, value ){ |
65 | var row_data = this.getRecord( record_id ).getData(), |
66 | merged_data = row_data[ STRING_STATENAME ] || {}; |
67 | |
68 | merged_data[ key ] = value; |
69 | |
70 | this.getRecord(record_id).setData(STRING_STATENAME, merged_data); |
71 | |
72 | return merged_data; |
73 | |
74 | }, |
75 | |
76 | ////////////////////////////////////////////////////////////////////// |
77 | // |
78 | // Public methods |
79 | // |
80 | ////////////////////////////////////////////////////////////////////// |
81 | |
82 | /** |
83 | * Over-ridden initAttributes method from DataTable |
84 | * @method initAttributes |
85 | * @param {Mixed} record_id Record / Row / or Index id |
86 | * @param {String} key Key to use in map |
87 | * @param {Mixed} value Value to assign to the key |
88 | * @return {Object} State data object |
89 | * @type mixed |
90 | **/ |
91 | initAttributes : function( oConfigs ) { |
92 | |
93 | oConfigs = oConfigs || {}; |
94 | |
95 | YAHOO.widget.DataTable.superclass.initAttributes.call(this, |
96 | oConfigs); |
97 | |
98 | /** |
99 | * @attribute rowExpansionTemplate |
100 | * @description Value for the rowExpansionTemplate attribute. |
101 | * @type {Mixed} |
102 | * @default "" |
103 | **/ |
104 | this.setAttributeConfig("rowExpansionTemplate", { |
105 | value: "", |
106 | validator: function( template ){ |
107 | return ( |
108 | YAHOO.lang.isString( template ) || |
109 | YAHOO.lang.isFunction( template ) |
110 | ); |
111 | }, |
112 | method: this.initRowExpansion |
113 | }); |
114 | |
115 | }, |
116 | |
117 | /** |
118 | * Initializes row expansion on the DataTable instance |
119 | * @method initRowExpansion |
120 | * @param {Mixed} template a string template or function to be |
121 | * called when Row is expanded |
122 | * @type mixed |
123 | **/ |
124 | initRowExpansion : function( template ){ |
125 | //Set subscribe restore method |
126 | this.subscribe('postRenderEvent', |
127 | this.onEventRestoreRowExpansion); |
128 | |
129 | //Setup template |
130 | this.rowExpansionTemplate = template; |
131 | |
132 | //Set table level state |
133 | this.a_rowExpansions = []; |
134 | }, |
135 | |
136 | /** |
137 | * Toggles the expansion state of a row |
138 | * @method toggleRowExpansion |
139 | * @param {Mixed} record_id Record / Row / or Index id |
140 | * @type mixed |
141 | **/ |
142 | toggleRowExpansion : function( record_id ){ |
143 | var state = this._getRecordState( record_id ); |
144 | |
145 | if( state && state.expanded ){ |
146 | this.collapseRow( record_id ); |
147 | } else { |
148 | this.expandRow( record_id ); |
149 | } |
150 | }, |
151 | |
152 | /** |
153 | * Sets the expansion state of a row to expanded |
154 | * @method expandRow |
155 | * @param {Mixed} record_id Record / Row / or Index id |
156 | * @param {Boolean} restore will restore an exisiting state for a |
157 | * row that has been collapsed by a non user action |
158 | * @return {Boolean} successful |
159 | * @type mixed |
160 | **/ |
161 | expandRow : function( record_id, restore ){ |
162 | |
163 | var state = this._getRecordState( record_id ); |
164 | |
165 | if( !state.expanded || restore ){ |
166 | |
167 | var row_data = this.getRecord( record_id ), |
168 | row = this.getRow( row_data ), |
169 | new_row = document.createElement('tr'), |
170 | column_length = this.getFirstTrEl().childNodes.length, |
171 | expanded_data = row_data.getData(), |
172 | expanded_content = null, |
173 | template = this.rowExpansionTemplate, |
174 | next_sibling = Dom.getNextSibling( row ); |
175 | |
176 | //Construct expanded row body |
177 | new_row.className = CLASS_EXPANSION; |
178 | var new_column = document.createElement( 'td' ); |
179 | new_column.colSpan = column_length; |
180 | |
181 | new_column.innerHTML = '<div class="'+CLASS_LINER+'"></div>'; |
182 | new_row.appendChild( new_column ); |
183 | |
184 | var liner_element = new_row.firstChild.firstChild; |
185 | |
186 | if( YAHOO.lang.isString( template ) ){ |
187 | |
188 | liner_element.innerHTML = YAHOO.lang.substitute( |
189 | template, |
190 | expanded_data |
191 | ); |
192 | |
193 | } else if( YAHOO.lang.isFunction( template ) ) { |
194 | |
195 | template( { |
196 | row_element : new_row, |
197 | liner_element : liner_element, |
198 | data : row_data, |
199 | state : state |
200 | |
201 | } ); |
202 | |
203 | } else { |
204 | return false; |
205 | } |
206 | |
207 | //Insert new row |
208 | newRow = Dom.insertAfter( new_row, row ); |
209 | |
210 | if (newRow.innerHTML.length) { |
211 | |
212 | this._setRecordState( record_id, 'expanded', true ); |
213 | |
214 | if( !restore ){ |
215 | this.a_rowExpansions.push( |
216 | this.getRecord(record_id).getId() |
217 | ); |
218 | } |
219 | |
220 | Dom.removeClass( row, CLASS_COLLAPSED ); |
221 | Dom.addClass( row, CLASS_EXPANDED ); |
222 | |
223 | //Fire custom event |
224 | this.fireEvent( "rowExpandEvent", |
225 | { record_id : row_data.getId() } ); |
226 | |
227 | return true; |
228 | } else { |
229 | return false; |
230 | } |
231 | } |
232 | }, |
233 | |
234 | /** |
235 | * Sets the expansion state of a row to collapsed |
236 | * @method collapseRow |
237 | * @param {Mixed} record_id Record / Row / or Index id |
238 | * @return {Boolean} successful |
239 | * @type mixed |
240 | **/ |
241 | collapseRow : function( record_id ){ |
242 | var row_data = this.getRecord( record_id ), |
243 | row = Dom.get( row_data.getId() ), |
244 | state = row_data.getData( STRING_STATENAME ); |
245 | |
246 | if( state && state.expanded ){ |
247 | var next_sibling = Dom.getNextSibling( row ), |
248 | hash_index = indexOf(this.a_rowExpansions, record_id); |
249 | |
250 | if( Dom.hasClass( next_sibling, CLASS_EXPANSION ) ) { |
251 | next_sibling.parentNode.removeChild( next_sibling ); |
252 | this.a_rowExpansions.splice( hash_index, 1 ); |
253 | this._setRecordState( record_id, 'expanded', false ); |
254 | |
255 | Dom.addClass( row, CLASS_COLLAPSED ); |
256 | Dom.removeClass( row, CLASS_EXPANDED ); |
257 | |
258 | //Fire custom event |
259 | this.fireEvent("rowCollapseEvent", |
260 | {record_id:row_data.getId()}); |
261 | |
262 | return true; |
263 | } else { |
264 | return false; |
265 | } |
266 | } |
267 | }, |
268 | |
269 | /** |
270 | * Collapses all expanded rows. This should be called before any |
271 | * action where the row expansion markup would interfere with |
272 | * normal DataTable markup handling. This method does not remove |
273 | * events attached during implementation. All event handlers should |
274 | * be removed separately. |
275 | * @method collapseAllRows |
276 | * @type mixed |
277 | **/ |
278 | collapseAllRows : function(){ |
279 | var rows = this.a_rowExpansions; |
280 | |
281 | for( var i = 0, l = rows.length; l > i; i++ ){ |
282 | //Always pass 0 since collapseRow |
283 | //removes item from the a_rowExpansions array |
284 | this.collapseRow( rows[ 0 ] ); |
285 | |
286 | } |
287 | |
288 | a_rowExpansions = []; |
289 | |
290 | }, |
291 | |
292 | /** |
293 | * Restores rows which have an expanded state but no markup. This |
294 | * is to be called to restore row expansions after the DataTable |
295 | * renders or the collapseAllRows is called. |
296 | * @method collapseAllRows |
297 | * @type mixed |
298 | **/ |
299 | restoreExpandedRows : function(){ |
300 | var expanded_rows = this.a_rowExpansions; |
301 | |
302 | if( !expanded_rows.length ){ |
303 | return; |
304 | } |
305 | |
306 | if( this.a_rowExpansions.length ){ |
307 | for( var i = 0, l = expanded_rows.length; l > i; i++ ){ |
308 | this.expandRow( expanded_rows[ i ] , true ); |
309 | } |
310 | } |
311 | }, |
312 | |
313 | /** |
314 | * Abstract method which restores row expansion for subscribing to |
315 | * the DataTable postRenderEvent. |
316 | * @method onEventRestoreRowExpansion |
317 | * @param {Object} oArgs context of a subscribed event |
318 | * @type mixed |
319 | **/ |
320 | onEventRestoreRowExpansion : function( oArgs ){ |
321 | this.restoreExpandedRows(); |
322 | }, |
323 | |
324 | /** |
325 | * Abstract method which toggles row expansion for subscribing to |
326 | * the DataTable postRenderEvent. |
327 | * @method onEventToggleRowExpansion |
328 | * @param {Object} oArgs context of a subscribed event |
329 | * @type mixed |
330 | **/ |
331 | onEventToggleRowExpansion : function( oArgs ){ |
332 | if(YAHOO.util.Dom.hasClass(oArgs.target, |
333 | 'yui-dt-expandablerow-trigger')){ |
334 | this.toggleRowExpansion( oArgs.target ); |
335 | } |
336 | } |
337 | |
338 | }, true //This boolean needed to override members of the original object |
339 | ); |
340 | |
341 | })(); |
view plain | print | ? |
JavaScript to run this example:
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.DataTable( |
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.
INFO 162ms (+162) 12:25:36 AM:
LogReader instance0
LogReader initialized
INFO 0ms (+0) 12:25:36 AM:
global
Logger initialized
Note: You are viewing this example in debug mode with logging enabled. This can significantly slow performance.
Copyright © 2009 Yahoo! Inc. All rights reserved.
Privacy Policy - Terms of Service - Copyright Policy - Job Openings