3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @docauthor Robert Dougan <rob@sencha.com>
18 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields. Also serves as a
19 * parent class for {@link Ext.form.field.Radio radio buttons}.
23 * In addition to the {@link Ext.form.Labelable standard field labeling options}, checkboxes
24 * may be given an optional {@link #boxLabel} which will be displayed immediately after checkbox. Also see
25 * {@link Ext.form.CheckboxGroup} for a convenient method of grouping related checkboxes.
29 * The main value of a checkbox is a boolean, indicating whether or not the checkbox is checked.
30 * The following values will check the checkbox:
37 * Any other value will uncheck the checkbox.
39 * In addition to the main boolean value, you may also specify a separate {@link #inputValue}. This will be
40 * sent as the parameter value when the form is {@link Ext.form.Basic#submit submitted}. You will want to set
41 * this value if you have multiple checkboxes with the same {@link #name}. If not specified, the value `on`
47 * Ext.create('Ext.form.Panel', {
50 * title: 'Pizza Order',
53 * xtype: 'fieldcontainer',
54 * fieldLabel: 'Toppings',
55 * defaultType: 'checkboxfield',
58 * boxLabel : 'Anchovies',
63 * boxLabel : 'Artichoke Hearts',
79 * text: 'Select Bacon',
80 * handler: function() {
81 * Ext.getCmp('checkbox3').setValue(true);
87 * handler: function() {
88 * Ext.getCmp('checkbox1').setValue(true);
89 * Ext.getCmp('checkbox2').setValue(true);
90 * Ext.getCmp('checkbox3').setValue(true);
94 * text: 'Deselect All',
95 * handler: function() {
96 * Ext.getCmp('checkbox1').setValue(false);
97 * Ext.getCmp('checkbox2').setValue(false);
98 * Ext.getCmp('checkbox3').setValue(false);
102 * renderTo: Ext.getBody()
105 Ext.define('Ext.form.field.Checkbox', {
106 extend: 'Ext.form.field.Base',
107 alias: ['widget.checkboxfield', 'widget.checkbox'],
108 alternateClassName: 'Ext.form.Checkbox',
109 requires: ['Ext.XTemplate', 'Ext.form.CheckboxManager'],
111 // note: {id} here is really {inputId}, but {cmpId} is available
113 '<tpl if="boxLabel && boxLabelAlign == \'before\'">',
114 '<label id="{cmpId}-boxLabelEl" class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">{boxLabel}</label>',
116 // Creates not an actual checkbox, but a button which is given aria role="checkbox" and
117 // styled with a custom checkbox image. This allows greater control and consistency in
118 // styling, and using a button allows it to gain focus and handle keyboard nav properly.
119 '<input type="button" id="{id}" ',
120 '<tpl if="tabIdx">tabIndex="{tabIdx}" </tpl>',
121 'class="{fieldCls} {typeCls}" autocomplete="off" hidefocus="true" />',
122 '<tpl if="boxLabel && boxLabelAlign == \'after\'">',
123 '<label id="{cmpId}-boxLabelEl" class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">{boxLabel}</label>',
126 disableFormats: true,
134 * @cfg {String} [focusCls='x-form-cb-focus']
135 * The CSS class to use when the checkbox receives focus
137 focusCls: Ext.baseCSSPrefix + 'form-cb-focus',
140 * @cfg {String} [fieldCls='x-form-field']
141 * The default CSS class for the checkbox
145 * @cfg {String} [fieldBodyCls='x-form-cb-wrap']
146 * An extra CSS class to be applied to the body content element in addition to {@link #fieldBodyCls}.
149 fieldBodyCls: Ext.baseCSSPrefix + 'form-cb-wrap',
152 * @cfg {Boolean} checked
153 * true if the checkbox should render initially checked
158 * @cfg {String} [checkedCls='x-form-cb-checked']
159 * The CSS class added to the component's main element when it is in the checked state.
161 checkedCls: Ext.baseCSSPrefix + 'form-cb-checked',
164 * @cfg {String} boxLabel
165 * An optional text label that will appear next to the checkbox. Whether it appears before or after the checkbox is
166 * determined by the {@link #boxLabelAlign} config.
170 * @cfg {String} [boxLabelCls='x-form-cb-label']
171 * The CSS class to be applied to the {@link #boxLabel} element
173 boxLabelCls: Ext.baseCSSPrefix + 'form-cb-label',
176 * @cfg {String} boxLabelAlign
177 * The position relative to the checkbox where the {@link #boxLabel} should appear. Recognized values are 'before'
180 boxLabelAlign: 'after',
183 * @cfg {String} inputValue
184 * The value that should go into the generated input element's value attribute and should be used as the parameter
185 * value when submitting as part of a form.
190 * @cfg {String} uncheckedValue
191 * If configured, this will be submitted as the checkbox's value during form submit if the checkbox is unchecked. By
192 * default this is undefined, which results in nothing being submitted for the checkbox field when the form is
193 * submitted (the default behavior of HTML checkboxes).
197 * @cfg {Function} handler
198 * A function called when the {@link #checked} value changes (can be used instead of handling the {@link #change
200 * @cfg {Ext.form.field.Checkbox} handler.checkbox The Checkbox being toggled.
201 * @cfg {Boolean} handler.checked The new checked state of the checkbox.
205 * @cfg {Object} scope
206 * An object to use as the scope ('this' reference) of the {@link #handler} function (defaults to this Checkbox).
210 checkChangeEvents: [],
211 inputType: 'checkbox',
212 ariaRole: 'checkbox',
217 initComponent: function(){
218 this.callParent(arguments);
219 this.getManager().add(this);
222 initValue: function() {
224 checked = !!me.checked;
227 * @property {Object} originalValue
228 * The original value of the field as configured in the {@link #checked} configuration, or as loaded by the last
229 * form load operation if the form's {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} setting is `true`.
231 me.originalValue = me.lastValue = checked;
233 // Set the initial checked state
234 me.setValue(checked);
238 onRender : function(ct, position) {
242 * @property {Ext.Element} boxLabelEl
243 * A reference to the label element created for the {@link #boxLabel}. Only present if the component has been
244 * rendered and has a boxLabel configured.
246 me.addChildEls('boxLabelEl');
248 Ext.applyIf(me.subTplData, {
249 boxLabel: me.boxLabel,
250 boxLabelCls: me.boxLabelCls,
251 boxLabelAlign: me.boxLabelAlign
254 me.callParent(arguments);
257 initEvents: function() {
260 me.mon(me.inputEl, 'click', me.onBoxClick, me);
264 * @private Handle click on the checkbox button
266 onBoxClick: function(e) {
268 if (!me.disabled && !me.readOnly) {
269 this.setValue(!this.checked);
274 * Returns the checked state of the checkbox.
275 * @return {Boolean} True if checked, else false
277 getRawValue: function() {
282 * Returns the checked state of the checkbox.
283 * @return {Boolean} True if checked, else false
285 getValue: function() {
290 * Returns the submit value for the checkbox which can be used when submitting forms.
291 * @return {Boolean/Object} True if checked; otherwise either the {@link #uncheckedValue} or null.
293 getSubmitValue: function() {
294 var unchecked = this.uncheckedValue,
295 uncheckedVal = Ext.isDefined(unchecked) ? unchecked : null;
296 return this.checked ? this.inputValue : uncheckedVal;
300 * Sets the checked state of the checkbox.
302 * @param {Boolean/String/Number} value The following values will check the checkbox:
303 * `true, 'true', '1', 1, or 'on'`, as well as a String that matches the {@link #inputValue}.
304 * Any other value will uncheck the checkbox.
305 * @return {Boolean} the new checked state of the checkbox
307 setRawValue: function(value) {
309 inputEl = me.inputEl,
310 inputValue = me.inputValue,
311 checked = (value === true || value === 'true' || value === '1' || value === 1 ||
312 (((Ext.isString(value) || Ext.isNumber(value)) && inputValue) ? value == inputValue : me.onRe.test(value)));
315 inputEl.dom.setAttribute('aria-checked', checked);
316 me[checked ? 'addCls' : 'removeCls'](me.checkedCls);
319 me.checked = me.rawValue = checked;
324 * Sets the checked state of the checkbox, and invokes change detection.
325 * @param {Boolean/String} checked The following values will check the checkbox: `true, 'true', '1', or 'on'`, as
326 * well as a String that matches the {@link #inputValue}. Any other value will uncheck the checkbox.
327 * @return {Ext.form.field.Checkbox} this
329 setValue: function(checked) {
332 // If an array of strings is passed, find all checkboxes in the group with the same name as this
333 // one and check all those whose inputValue is in the array, unchecking all the others. This is to
334 // facilitate setting values from Ext.form.Basic#setValues, but is not publicly documented as we
335 // don't want users depending on this behavior.
336 if (Ext.isArray(checked)) {
337 me.getManager().getByName(me.name).each(function(cb) {
338 cb.setValue(Ext.Array.contains(checked, cb.inputValue));
341 me.callParent(arguments);
348 valueToRaw: function(value) {
349 // No extra conversion for checkboxes
355 * Called when the checkbox's checked state changes. Invokes the {@link #handler} callback
356 * function if specified.
358 onChange: function(newVal, oldVal) {
360 handler = me.handler;
362 handler.call(me.scope || me, me, newVal);
364 me.callParent(arguments);
368 beforeDestroy: function(){
370 this.getManager().removeAtKey(this.id);
374 getManager: function() {
375 return Ext.form.CheckboxManager;
378 onEnable: function() {
380 inputEl = me.inputEl;
383 // Can still be disabled if the field is readOnly
384 inputEl.dom.disabled = me.readOnly;
388 setReadOnly: function(readOnly) {
390 inputEl = me.inputEl;
392 // Set the button to disabled when readonly
393 inputEl.dom.disabled = readOnly || me.disabled;
395 me.readOnly = readOnly;
398 // Calculates and returns the natural width of the bodyEl. It's possible that the initial rendering will
399 // cause the boxLabel to wrap and give us a bad width, so we must prevent wrapping while measuring.
400 getBodyNaturalWidth: function() {
405 bodyEl.setStyle(ws, 'nowrap');
406 width = bodyEl.getWidth();
407 bodyEl.setStyle(ws, '');