/**
* @class Ext.form.field.Checkbox
* @extends Ext.form.field.Base
Single checkbox field. Can be used as a direct replacement for traditional checkbox fields. Also serves as a
parent class for {@link Ext.form.field.Radio radio buttons}.
__Labeling:__ In addition to the {@link Ext.form.Labelable standard field labeling options}, checkboxes
may be given an optional {@link #boxLabel} which will be displayed immediately after checkbox. Also see
{@link Ext.form.CheckboxGroup} for a convenient method of grouping related checkboxes.
__Values:__
The main value of a checkbox is a boolean, indicating whether or not the checkbox is checked.
The following values will check the checkbox:
* `true`
* `'true'`
* `'1'`
* `'on'`
Any other value will uncheck the checkbox.
In addition to the main boolean value, you may also specify a separate {@link #inputValue}. This will be
sent as the parameter value when the form is {@link Ext.form.Basic#submit submitted}. You will want to set
this value if you have multiple checkboxes with the same {@link #name}. If not specified, the value `on`
will be used.
{@img Ext.form.Checkbox/Ext.form.Checkbox.png Ext.form.Checkbox Checkbox component}
__Example usage:__
Ext.create('Ext.form.Panel', {
bodyPadding: 10,
width : 300,
title : 'Pizza Order',
items: [
{
xtype : 'fieldcontainer',
fieldLabel : 'Toppings',
defaultType: 'checkboxfield',
items: [
{
boxLabel : 'Anchovies',
name : 'topping',
inputValue: '1',
id : 'checkbox1'
}, {
boxLabel : 'Artichoke Hearts',
name : 'topping',
inputValue: '2',
checked : true,
id : 'checkbox2'
}, {
boxLabel : 'Bacon',
name : 'topping',
inputValue: '3',
id : 'checkbox3'
}
]
}
],
bbar: [
{
text: 'Select Bacon',
handler: function() {
var checkbox = Ext.getCmp('checkbox3');
checkbox.setValue(true);
}
},
'-',
{
text: 'Select All',
handler: function() {
var checkbox1 = Ext.getCmp('checkbox1'),
checkbox2 = Ext.getCmp('checkbox2'),
checkbox3 = Ext.getCmp('checkbox3');
checkbox1.setValue(true);
checkbox2.setValue(true);
checkbox3.setValue(true);
}
},
{
text: 'Deselect All',
handler: function() {
var checkbox1 = Ext.getCmp('checkbox1'),
checkbox2 = Ext.getCmp('checkbox2'),
checkbox3 = Ext.getCmp('checkbox3');
checkbox1.setValue(false);
checkbox2.setValue(false);
checkbox3.setValue(false);
}
}
],
renderTo: Ext.getBody()
});
* @constructor
* Creates a new Checkbox
* @param {Object} config Configuration options
* @xtype checkboxfield
* @docauthor Robert Dougan <rob@sencha.com>
* @markdown
*/
Ext.define('Ext.form.field.Checkbox', {
extend: 'Ext.form.field.Base',
alias: ['widget.checkboxfield', 'widget.checkbox'],
alternateClassName: 'Ext.form.Checkbox',
requires: ['Ext.XTemplate', 'Ext.form.CheckboxManager'],
fieldSubTpl: [
'<tpl if="boxLabel && boxLabelAlign == \'before\'">',
'<label class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">{boxLabel}</label>',
'</tpl>',
// Creates not an actual checkbox, but a button which is given aria role="checkbox" and
// styled with a custom checkbox image. This allows greater control and consistency in
// styling, and using a button allows it to gain focus and handle keyboard nav properly.
'<input type="button" id="{id}" ',
'<tpl if="tabIdx">tabIndex="{tabIdx}" </tpl>',
'class="{fieldCls} {typeCls}" autocomplete="off" hidefocus="true" />',
'<tpl if="boxLabel && boxLabelAlign == \'after\'">',
'<label class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">{boxLabel}</label>',
'</tpl>',
{
disableFormats: true,
compiled: true
}
],
isCheckbox: true,
/**
* @cfg {String} focusCls The CSS class to use when the checkbox receives focus
* (defaults to <tt>'x-form-cb-focus'</tt>)
*/
focusCls: Ext.baseCSSPrefix + 'form-cb-focus',
/**
* @cfg {String} fieldCls The default CSS class for the checkbox (defaults to <tt>'x-form-field'</tt>)
*/
/**
* @cfg {String} fieldBodyCls
* An extra CSS class to be applied to the body content element in addition to {@link #fieldBodyCls}.
* Defaults to 'x-form-cb-wrap.
*/
fieldBodyCls: Ext.baseCSSPrefix + 'form-cb-wrap',
/**
* @cfg {Boolean} checked <tt>true</tt> if the checkbox should render initially checked (defaults to <tt>false</tt>)
*/
checked: false,
/**
* @cfg {String} checkedCls The CSS class added to the component's main element when it is in the checked state.
*/
checkedCls: Ext.baseCSSPrefix + 'form-cb-checked',
/**
* @cfg {String} boxLabel An optional text label that will appear next to the checkbox. Whether it appears before
* or after the checkbox is determined by the {@link #boxLabelAlign} config (defaults to after).
*/
/**
* @cfg {String} boxLabelCls The CSS class to be applied to the {@link #boxLabel} element
*/
boxLabelCls: Ext.baseCSSPrefix + 'form-cb-label',
/**
* @cfg {String} boxLabelAlign The position relative to the checkbox where the {@link #boxLabel} should
* appear. Recognized values are <tt>'before'</tt> and <tt>'after'</tt>. Defaults to <tt>'after'</tt>.
*/
boxLabelAlign: 'after',
/**
* @cfg {String} inputValue The value that should go into the generated input element's value attribute and
* should be used as the parameter value when submitting as part of a form. Defaults to <tt>"on"</tt>.
*/
inputValue: 'on',
/**
* @cfg {String} uncheckedValue If configured, this will be submitted as the checkbox's value during form
* submit if the checkbox is unchecked. By default this is undefined, which results in nothing being
* submitted for the checkbox field when the form is submitted (the default behavior of HTML checkboxes).
*/
/**
* @cfg {Function} handler A function called when the {@link #checked} value changes (can be used instead of
* handling the {@link #change change event}). The handler is passed the following parameters:
* <div class="mdetail-params"><ul>
* <li><b>checkbox</b> : Ext.form.field.Checkbox<div class="sub-desc">The Checkbox being toggled.</div></li>
* <li><b>checked</b> : Boolean<div class="sub-desc">The new checked state of the checkbox.</div></li>
* </ul></div>
*/
/**
* @cfg {Object} scope An object to use as the scope ('this' reference) of the {@link #handler} function
* (defaults to this Checkbox).
*/
// private overrides
checkChangeEvents: [],
inputType: 'checkbox',
ariaRole: 'checkbox',
// private
onRe: /^on$/i,
initComponent: function(){
this.callParent(arguments);
this.getManager().add(this);
},
initValue: function() {
var me = this,
checked = !!me.checked;
/**
* The original value of the field as configured in the {@link #checked} configuration, or
* as loaded by the last form load operation if the form's {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad}
* setting is <code>true</code>.
* @type Mixed
* @property originalValue
*/
me.originalValue = me.lastValue = checked;
// Set the initial checked state
me.setValue(checked);
},
// private
onRender : function(ct, position) {
var me = this;
Ext.applyIf(me.renderSelectors, {
/**
* @property boxLabelEl
* @type Ext.core.Element
* A reference to the label element created for the {@link #boxLabel}. Only present if the
* component has been rendered and has a boxLabel configured.
*/
boxLabelEl: 'label.' + me.boxLabelCls
});
Ext.applyIf(me.subTplData, {
boxLabel: me.boxLabel,
boxLabelCls: me.boxLabelCls,
boxLabelAlign: me.boxLabelAlign
});
me.callParent(arguments);
},
initEvents: function() {
var me = this;
me.callParent();
me.mon(me.inputEl, 'click', me.onBoxClick, me);
},
/**
* @private Handle click on the checkbox button
*/
onBoxClick: function(e) {
var me = this;
if (!me.disabled && !me.readOnly) {
this.setValue(!this.checked);
}
},
/**
* Returns the checked state of the checkbox.
* @return {Boolean} True if checked, else false
*/
getRawValue: function() {
return this.checked;
},
/**
* Returns the checked state of the checkbox.
* @return {Boolean} True if checked, else false
*/
getValue: function() {
return this.checked;
},
/**
* Returns the submit value for the checkbox which can be used when submitting forms.
* @return {Boolean/null} True if checked; otherwise either the {@link #uncheckedValue} or null.
*/
getSubmitValue: function() {
return this.checked ? this.inputValue : (this.uncheckedValue || null);
},
getModelData: function() {
return this.getSubmitData();
},
/**
* Sets the checked state of the checkbox.
* @param {Boolean/String} value The following values will check the checkbox:
* <code>true, 'true', '1', or 'on'</code>, as well as a String that matches the {@link #inputValue}.
* Any other value will uncheck the checkbox.
* @return {Boolean} the new checked state of the checkbox
*/
setRawValue: function(value) {
var me = this,
inputEl = me.inputEl,
inputValue = me.inputValue,
checked = (value === true || value === 'true' || value === '1' ||
((Ext.isString(value) && inputValue) ? value == inputValue : me.onRe.test(value)));
if (inputEl) {
inputEl.dom.setAttribute('aria-checked', checked);
me[checked ? 'addCls' : 'removeCls'](me.checkedCls);
}
me.checked = me.rawValue = checked;
return checked;
},
/**
* Sets the checked state of the checkbox, and invokes change detection.
* @param {Boolean/String} checked The following values will check the checkbox:
* <code>true, 'true', '1', or 'on'</code>, as well as a String that matches the {@link #inputValue}.
* Any other value will uncheck the checkbox.
* @return {Ext.form.field.Checkbox} this
*/
setValue: function(checked) {
var me = this;
// If an array of strings is passed, find all checkboxes in the group with the same name as this
// one and check all those whose inputValue is in the array, unchecking all the others. This is to
// facilitate setting values from Ext.form.Basic#setValues, but is not publicly documented as we
// don't want users depending on this behavior.
if (Ext.isArray(checked)) {
me.getManager().getByName(me.name).each(function(cb) {
cb.setValue(Ext.Array.contains(checked, cb.inputValue));
});
} else {
me.callParent(arguments);
}
return me;
},
// private
valueToRaw: function(value) {
// No extra conversion for checkboxes
return value;
},
/**
* @private
* Called when the checkbox's checked state changes. Invokes the {@link #handler} callback
* function if specified.
*/
onChange: function(newVal, oldVal) {
var me = this,
handler = me.handler;
if (handler) {
handler.call(me.scope || me, me, newVal);
}
me.callParent(arguments);
},
// inherit docs
getManager: function() {
return Ext.form.CheckboxManager;
},
onEnable: function() {
var me = this,
inputEl = me.inputEl;
me.callParent();
if (inputEl) {
// Can still be disabled if the field is readOnly
inputEl.dom.disabled = me.readOnly;
}
},
setReadOnly: function(readOnly) {
var me = this,
inputEl = me.inputEl;
if (inputEl) {
// Set the button to disabled when readonly
inputEl.dom.disabled = readOnly || me.disabled;
}
me.readOnly = readOnly;
},
/**
* @protected Calculate and return the natural width of the bodyEl. It's possible that the initial
* rendering will cause the boxLabel to wrap and give us a bad width, so we must prevent wrapping
* while measuring.
*/
getBodyNaturalWidth: function() {
var me = this,
bodyEl = me.bodyEl,
ws = 'white-space',
width;
bodyEl.setStyle(ws, 'nowrap');
width = bodyEl.getWidth();
bodyEl.setStyle(ws, '');
return width;
}
});