Upgrade to ExtJS 3.3.0 - Released 10/06/2010
[extjs.git] / docs / source / CheckboxGroup.html
1 <html>
2 <head>
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    
4   <title>The source code</title>
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
7 </head>
8 <body  onload="prettyPrint();">
9     <pre class="prettyprint lang-js">/*!
10  * Ext JS Library 3.3.0
11  * Copyright(c) 2006-2010 Ext JS, Inc.
12  * licensing@extjs.com
13  * http://www.extjs.com/license
14  */
15 <div id="cls-Ext.form.CheckboxGroup"></div>/**
16  * @class Ext.form.CheckboxGroup
17  * @extends Ext.form.Field
18  * <p>A grouping container for {@link Ext.form.Checkbox} controls.</p>
19  * <p>Sample usage:</p>
20  * <pre><code>
21 var myCheckboxGroup = new Ext.form.CheckboxGroup({
22     id:'myGroup',
23     xtype: 'checkboxgroup',
24     fieldLabel: 'Single Column',
25     itemCls: 'x-check-group-alt',
26     // Put all controls in a single column with width 100%
27     columns: 1,
28     items: [
29         {boxLabel: 'Item 1', name: 'cb-col-1'},
30         {boxLabel: 'Item 2', name: 'cb-col-2', checked: true},
31         {boxLabel: 'Item 3', name: 'cb-col-3'}
32     ]
33 });
34  * </code></pre>
35  * @constructor
36  * Creates a new CheckboxGroup
37  * @param {Object} config Configuration options
38  * @xtype checkboxgroup
39  */
40 Ext.form.CheckboxGroup = Ext.extend(Ext.form.Field, {
41     <div id="cfg-Ext.form.CheckboxGroup-items"></div>/**
42      * @cfg {Array} items An Array of {@link Ext.form.Checkbox Checkbox}es or Checkbox config objects
43      * to arrange in the group.
44      */
45     <div id="cfg-Ext.form.CheckboxGroup-columns"></div>/**
46      * @cfg {String/Number/Array} columns Specifies the number of columns to use when displaying grouped
47      * checkbox/radio controls using automatic layout.  This config can take several types of values:
48      * <ul><li><b>'auto'</b> : <p class="sub-desc">The controls will be rendered one per column on one row and the width
49      * of each column will be evenly distributed based on the width of the overall field container. This is the default.</p></li>
50      * <li><b>Number</b> : <p class="sub-desc">If you specific a number (e.g., 3) that number of columns will be
51      * created and the contained controls will be automatically distributed based on the value of {@link #vertical}.</p></li>
52      * <li><b>Array</b> : Object<p class="sub-desc">You can also specify an array of column widths, mixing integer
53      * (fixed width) and float (percentage width) values as needed (e.g., [100, .25, .75]). Any integer values will
54      * be rendered first, then any float values will be calculated as a percentage of the remaining space. Float
55      * values do not have to add up to 1 (100%) although if you want the controls to take up the entire field
56      * container you should do so.</p></li></ul>
57      */
58     columns : 'auto',
59     <div id="cfg-Ext.form.CheckboxGroup-vertical"></div>/**
60      * @cfg {Boolean} vertical True to distribute contained controls across columns, completely filling each column
61      * top to bottom before starting on the next column.  The number of controls in each column will be automatically
62      * calculated to keep columns as even as possible.  The default value is false, so that controls will be added
63      * to columns one at a time, completely filling each row left to right before starting on the next row.
64      */
65     vertical : false,
66     <div id="cfg-Ext.form.CheckboxGroup-allowBlank"></div>/**
67      * @cfg {Boolean} allowBlank False to validate that at least one item in the group is checked (defaults to true).
68      * If no items are selected at validation time, {@link @blankText} will be used as the error text.
69      */
70     allowBlank : true,
71     <div id="cfg-Ext.form.CheckboxGroup-blankText"></div>/**
72      * @cfg {String} blankText Error text to display if the {@link #allowBlank} validation fails (defaults to "You must
73      * select at least one item in this group")
74      */
75     blankText : "You must select at least one item in this group",
76
77     // private
78     defaultType : 'checkbox',
79
80     // private
81     groupCls : 'x-form-check-group',
82
83     // private
84     initComponent: function(){
85         this.addEvents(
86             <div id="event-Ext.form.CheckboxGroup-change"></div>/**
87              * @event change
88              * Fires when the state of a child checkbox changes.
89              * @param {Ext.form.CheckboxGroup} this
90              * @param {Array} checked An array containing the checked boxes.
91              */
92             'change'
93         );
94         this.on('change', this.validate, this);
95         Ext.form.CheckboxGroup.superclass.initComponent.call(this);
96     },
97
98     // private
99     onRender : function(ct, position){
100         if(!this.el){
101             var panelCfg = {
102                 autoEl: {
103                     id: this.id
104                 },
105                 cls: this.groupCls,
106                 layout: 'column',
107                 renderTo: ct,
108                 bufferResize: false // Default this to false, since it doesn't really have a proper ownerCt.
109             };
110             var colCfg = {
111                 xtype: 'container',
112                 defaultType: this.defaultType,
113                 layout: 'form',
114                 defaults: {
115                     hideLabel: true,
116                     anchor: '100%'
117                 }
118             };
119
120             if(this.items[0].items){
121
122                 // The container has standard ColumnLayout configs, so pass them in directly
123
124                 Ext.apply(panelCfg, {
125                     layoutConfig: {columns: this.items.length},
126                     defaults: this.defaults,
127                     items: this.items
128                 });
129                 for(var i=0, len=this.items.length; i<len; i++){
130                     Ext.applyIf(this.items[i], colCfg);
131                 }
132
133             }else{
134
135                 // The container has field item configs, so we have to generate the column
136                 // panels first then move the items into the columns as needed.
137
138                 var numCols, cols = [];
139
140                 if(typeof this.columns == 'string'){ // 'auto' so create a col per item
141                     this.columns = this.items.length;
142                 }
143                 if(!Ext.isArray(this.columns)){
144                     var cs = [];
145                     for(var i=0; i<this.columns; i++){
146                         cs.push((100/this.columns)*.01); // distribute by even %
147                     }
148                     this.columns = cs;
149                 }
150
151                 numCols = this.columns.length;
152
153                 // Generate the column configs with the correct width setting
154                 for(var i=0; i<numCols; i++){
155                     var cc = Ext.apply({items:[]}, colCfg);
156                     cc[this.columns[i] <= 1 ? 'columnWidth' : 'width'] = this.columns[i];
157                     if(this.defaults){
158                         cc.defaults = Ext.apply(cc.defaults || {}, this.defaults);
159                     }
160                     cols.push(cc);
161                 };
162
163                 // Distribute the original items into the columns
164                 if(this.vertical){
165                     var rows = Math.ceil(this.items.length / numCols), ri = 0;
166                     for(var i=0, len=this.items.length; i<len; i++){
167                         if(i>0 && i%rows==0){
168                             ri++;
169                         }
170                         if(this.items[i].fieldLabel){
171                             this.items[i].hideLabel = false;
172                         }
173                         cols[ri].items.push(this.items[i]);
174                     };
175                 }else{
176                     for(var i=0, len=this.items.length; i<len; i++){
177                         var ci = i % numCols;
178                         if(this.items[i].fieldLabel){
179                             this.items[i].hideLabel = false;
180                         }
181                         cols[ci].items.push(this.items[i]);
182                     };
183                 }
184
185                 Ext.apply(panelCfg, {
186                     layoutConfig: {columns: numCols},
187                     items: cols
188                 });
189             }
190
191             this.panel = new Ext.Container(panelCfg);
192             this.panel.ownerCt = this;
193             this.el = this.panel.getEl();
194
195             if(this.forId && this.itemCls){
196                 var l = this.el.up(this.itemCls).child('label', true);
197                 if(l){
198                     l.setAttribute('htmlFor', this.forId);
199                 }
200             }
201
202             var fields = this.panel.findBy(function(c){
203                 return c.isFormField;
204             }, this);
205
206             this.items = new Ext.util.MixedCollection();
207             this.items.addAll(fields);
208         }
209         Ext.form.CheckboxGroup.superclass.onRender.call(this, ct, position);
210     },
211
212     initValue : function(){
213         if(this.value){
214             this.setValue.apply(this, this.buffered ? this.value : [this.value]);
215             delete this.buffered;
216             delete this.value;
217         }
218     },
219
220     afterRender : function(){
221         Ext.form.CheckboxGroup.superclass.afterRender.call(this);
222         this.eachItem(function(item){
223             item.on('check', this.fireChecked, this);
224             item.inGroup = true;
225         });
226     },
227
228     // private
229     doLayout: function(){
230         //ugly method required to layout hidden items
231         if(this.rendered){
232             this.panel.forceLayout = this.ownerCt.forceLayout;
233             this.panel.doLayout();
234         }
235     },
236
237     // private
238     fireChecked: function(){
239         var arr = [];
240         this.eachItem(function(item){
241             if(item.checked){
242                 arr.push(item);
243             }
244         });
245         this.fireEvent('change', this, arr);
246     },
247     
248     <div id="method-Ext.form.CheckboxGroup-getErrors"></div>/**
249      * Runs CheckboxGroup's validations and returns an array of any errors. The only error by default
250      * is if allowBlank is set to true and no items are checked.
251      * @return {Array} Array of all validation errors
252      */
253     getErrors: function() {
254         var errors = Ext.form.CheckboxGroup.superclass.getErrors.apply(this, arguments);
255         
256         if (!this.allowBlank) {
257             var blank = true;
258             
259             this.eachItem(function(f){
260                 if (f.checked) {
261                     return (blank = false);
262                 }
263             });
264             
265             if (blank) errors.push(this.blankText);
266         }
267         
268         return errors;
269     },
270
271     // private
272     isDirty: function(){
273         //override the behaviour to check sub items.
274         if (this.disabled || !this.rendered) {
275             return false;
276         }
277
278         var dirty = false;
279         
280         this.eachItem(function(item){
281             if(item.isDirty()){
282                 dirty = true;
283                 return false;
284             }
285         });
286         
287         return dirty;
288     },
289
290     // private
291     setReadOnly : function(readOnly){
292         if(this.rendered){
293             this.eachItem(function(item){
294                 item.setReadOnly(readOnly);
295             });
296         }
297         this.readOnly = readOnly;
298     },
299
300     // private
301     onDisable : function(){
302         this.eachItem(function(item){
303             item.disable();
304         });
305     },
306
307     // private
308     onEnable : function(){
309         this.eachItem(function(item){
310             item.enable();
311         });
312     },
313
314     // private
315     onResize : function(w, h){
316         this.panel.setSize(w, h);
317         this.panel.doLayout();
318     },
319
320     // inherit docs from Field
321     reset : function(){
322         if (this.originalValue) {
323             // Clear all items
324             this.eachItem(function(c){
325                 if(c.setValue){
326                     c.setValue(false);
327                     c.originalValue = c.getValue();
328                 }
329             });
330             // Set items stored in originalValue, ugly - set a flag to reset the originalValue
331             // during the horrible onSetValue.  This will allow trackResetOnLoad to function.
332             this.resetOriginal = true;
333             this.setValue(this.originalValue);
334             delete this.resetOriginal;
335         } else {
336             this.eachItem(function(c){
337                 if(c.reset){
338                     c.reset();
339                 }
340             });
341         }
342         // Defer the clearInvalid so if BaseForm's collection is being iterated it will be called AFTER it is complete.
343         // Important because reset is being called on both the group and the individual items.
344         (function() {
345             this.clearInvalid();
346         }).defer(50, this);
347     },
348
349     <div id="method-Ext.form.CheckboxGroup-setValue"></div>/**
350      * {@link Ext.form.Checkbox#setValue Set the value(s)} of an item or items
351      * in the group. Examples illustrating how this method may be called:
352      * <pre><code>
353 // call with name and value
354 myCheckboxGroup.setValue('cb-col-1', true);
355 // call with an array of boolean values
356 myCheckboxGroup.setValue([true, false, false]);
357 // call with an object literal specifying item:value pairs
358 myCheckboxGroup.setValue({
359     'cb-col-2': false,
360     'cb-col-3': true
361 });
362 // use comma separated string to set items with name to true (checked)
363 myCheckboxGroup.setValue('cb-col-1,cb-col-3');
364      * </code></pre>
365      * See {@link Ext.form.Checkbox#setValue} for additional information.
366      * @param {Mixed} id The checkbox to check, or as described by example shown.
367      * @param {Boolean} value (optional) The value to set the item.
368      * @return {Ext.form.CheckboxGroup} this
369      */
370     setValue: function(){
371         if(this.rendered){
372             this.onSetValue.apply(this, arguments);
373         }else{
374             this.buffered = true;
375             this.value = arguments;
376         }
377         return this;
378     },
379
380     /**
381      * @private
382      * Sets the values of one or more of the items within the CheckboxGroup
383      * @param {String|Array|Object} id Can take multiple forms. Can be optionally:
384      * <ul>
385      *   <li>An ID string to be used with a second argument</li>
386      *   <li>An array of the form ['some', 'list', 'of', 'ids', 'to', 'mark', 'checked']</li>
387      *   <li>An array in the form [true, true, false, true, false] etc, where each item relates to the check status of
388      *       the checkbox at the same index</li>
389      *   <li>An object containing ids of the checkboxes as keys and check values as properties</li>
390      * </ul>
391      * @param {String} value The value to set the field to if the first argument was a string
392      */
393     onSetValue: function(id, value){
394         if(arguments.length == 1){
395             if(Ext.isArray(id)){
396                 Ext.each(id, function(val, idx){
397                     if (Ext.isObject(val) && val.setValue){ // array of checkbox components to be checked
398                         val.setValue(true);
399                         if (this.resetOriginal === true) {
400                             val.originalValue = val.getValue();
401                         }
402                     } else { // an array of boolean values
403                         var item = this.items.itemAt(idx);
404                         if(item){
405                             item.setValue(val);
406                         }
407                     }
408                 }, this);
409             }else if(Ext.isObject(id)){
410                 // set of name/value pairs
411                 for(var i in id){
412                     var f = this.getBox(i);
413                     if(f){
414                         f.setValue(id[i]);
415                     }
416                 }
417             }else{
418                 this.setValueForItem(id);
419             }
420         }else{
421             var f = this.getBox(id);
422             if(f){
423                 f.setValue(value);
424             }
425         }
426     },
427
428     // private
429     beforeDestroy: function(){
430         Ext.destroy(this.panel);
431         if (!this.rendered) {
432             Ext.destroy(this.items);
433         }
434         Ext.form.CheckboxGroup.superclass.beforeDestroy.call(this);
435
436     },
437
438     setValueForItem : function(val){
439         val = String(val).split(',');
440         this.eachItem(function(item){
441             if(val.indexOf(item.inputValue)> -1){
442                 item.setValue(true);
443             }
444         });
445     },
446
447     // private
448     getBox : function(id){
449         var box = null;
450         this.eachItem(function(f){
451             if(id == f || f.dataIndex == id || f.id == id || f.getName() == id){
452                 box = f;
453                 return false;
454             }
455         });
456         return box;
457     },
458
459     <div id="method-Ext.form.CheckboxGroup-getValue"></div>/**
460      * Gets an array of the selected {@link Ext.form.Checkbox} in the group.
461      * @return {Array} An array of the selected checkboxes.
462      */
463     getValue : function(){
464         var out = [];
465         this.eachItem(function(item){
466             if(item.checked){
467                 out.push(item);
468             }
469         });
470         return out;
471     },
472
473     /**
474      * @private
475      * Convenience function which passes the given function to every item in the composite
476      * @param {Function} fn The function to call
477      * @param {Object} scope Optional scope object
478      */
479     eachItem: function(fn, scope) {
480         if(this.items && this.items.each){
481             this.items.each(fn, scope || this);
482         }
483     },
484
485     <div id="cfg-Ext.form.CheckboxGroup-name"></div>/**
486      * @cfg {String} name
487      * @hide
488      */
489
490     <div id="method-Ext.form.CheckboxGroup-getRawValue"></div>/**
491      * @method getRawValue
492      * @hide
493      */
494     getRawValue : Ext.emptyFn,
495
496     <div id="method-Ext.form.CheckboxGroup-setRawValue"></div>/**
497      * @method setRawValue
498      * @hide
499      */
500     setRawValue : Ext.emptyFn
501
502 });
503
504 Ext.reg('checkboxgroup', Ext.form.CheckboxGroup);
505 </pre>    
506 </body>
507 </html>