Submitting an Ext.form.Checkbox when unchecked
ExtJS is a great Javascript UI library and API. In using ExtJS for UI components to create forms, the Ext checkbox widget (Ext.form.Checkbox) mimics the behavior of standard HTML checkboxes in that if they are not checked, they are not submitted via POST/GET on the form. This makes sense in some instances, in that if I don’t set a value for a given checkbox field I probably don’t want it on the back-end – except when that checkbox represents an on/off type value and that value, whether on or off, needs to be updated in a database record somewhere.
So, what do you do in those instances where you want to know if a field value has been toggled off, and not just on? You could cycle through those particular boolean fields for each record you want to update, checking if the existing value is set on the record; and if that field isn’t present in the form POST data unset it explicitly. However, that’s a lot of work and a lot of hard-coding of boolean indicator fields on your back-end. A better solution would be if we could actually make those stubborn checkboxes send a value on form submission even when they aren’t checked! And lo and behold, with ExtJS’s Ext.override() functionality for classes, we can do that with the standard Ext.form.Checkbox component.
In the code below, we use Ext.override() to modify the basic Ext.form.Checkbox component to include a hidden input field that will contain the “off” or “unchecked” value that we want submitted via our forms. However, in order to avoid sending duplicate fields when the primary checkbox is checked (we don’t want to send an “on” and an “off” value) we remove that hidden field each time the checkbox is checked by overriding the setValue() method of Ext.form.Checkbox.
We only need to override two methods: Ext.form.Checkbox.onRender() and Ext.form.Checkbox.setValue() to handle all the cases we need. Here’s the code…
(function() {
origCheckboxRender = Ext.form.Checkbox.prototype.onRender;
origCheckboxSetValue = Ext.form.Checkbox.prototype.setValue;
Ext.override(Ext.form.Checkbox, {
onRender: function() {
// call the original onRender() function
origCheckboxRender.apply(this, arguments);
// Handle initial case based on this.checked
if (this.checked == false) {
this.noValEl = Ext.DomHelper.insertAfter(this.el, {
tag: 'input',
type: 'hidden',
value: '0',
name: this.getName()
}, true);
}
else {
this.noValEl = null;
}
},
setValue: function() {
// call original setValue() function
origCheckboxSetValue.apply(this, arguments);
if (this.checked) {
if (this.noValEl != null) {
// Remove the extra hidden element
Ext.select('input[id=' + this.noValEl.id + ']').remove();
this.noValEl = null;
}
}
else {
// Add our hidden element for (unchecked) value
this.noValEl = Ext.DomHelper.insertAfter(this.el, {
tag: 'input',
type: 'hidden',
value: '0',
name: this.getName()
}, true);
}
}
});
})();
Important to note here, and not completely necessary, is that we’re using a closure by wrapping our override in an anonymous function and immediately calling it to run the override. This simply keeps us from polluting the global namespace; and once the override is done there’s no need to reference any of those objects again anyway.
Before calling Ext.override(), we save the original functions for onRender() and setValue(), since we don’t want to lose any existing Checkbox functionality they provide, we simply want to make them do a bit more. We could have chosen to use Ext.extend() here and create an entirely new type of Checkbox that handled this functionality. But, in my case on this project, that would have impacted too many other applications that already depended on the original Checkbox functionality; and, we didn’t want to go through all of our code and change every occurrence of Checkbox to SmartCheckbox or some such. Too much regression testing at this point. So, we choose to override instead of extend – but if you have the opportunity, extending might be the better option and provide you with a way to set the “unchecked” value you want for each Checkbox instance.
So, in each overridden function we simply call the original function first to retain existing functionality and then add our bits to extend the object. We use Ext.DomHelper.insertAfter() to handle inserting the new hidden form field and it has the same name as the actual Checkbox field. If the checkbox starts off initially checked, we add the hidden field; and if not we simply set our noValEl variable to null. Same for setValue(), which is called each time the checkbox is “checked.”
This is the kind of simple solution that the ExtJS library allows you to perform and which makes it a very extendable API for cross-browser Javascript UI development. Enjoy!
Dave Atchley is a working software engineer with 15 years experience in systems programming, data warehousing, web design and web applications development. This is his professional blog where he rambles about all things software related, organizes his personal projects and (hopefully) deftly plugs his services as a freelance/contract developer for hire.





January 8th, 2010 at 10:54 am
Thanks for the useful snippet of code. I’ve been looking for a work around to this problem for awhile, and your solution is very clean and unintrusive. I look forward to more articles on EXTJS.
July 30th, 2010 at 12:18 pm
Hi man, thanks for the code, but is not working if you have two or more different checkboxes. The code for that case is this.
origCheckboxRender = Ext.form.Checkbox.prototype.onRender;
origCheckboxSetValue = Ext.form.Checkbox.prototype.setValue;
Ext.override(Ext.form.Checkbox, {
onRender: function() {
// call the original onRender() function
origCheckboxRender.apply(this, arguments);
if (this.noValEl != null) {
// Remove the extra hidden element
Ext.select(‘input[id=' + this.noValEl.id + ']‘).remove();
this.noValEl = null;
}
// Handle initial case based on this.checked
if (!this.checked) {
this.noValEl = Ext.DomHelper.insertAfter(this.el, {
tag: ‘input’,
type: ‘hidden’,
value: ‘false’,
name: this.getName()
}, true);
}
},
setValue: function() {
// call original setValue() function
origCheckboxSetValue.apply(this, arguments);
if (this.noValEl != null) {
// Remove the extra hidden element
Ext.select(‘input[id=' + this.noValEl.id + ']‘).remove();
this.noValEl = null;
}
if (!this.checked) {
// Add our hidden element for (unchecked) value
this.noValEl = Ext.DomHelper.insertAfter(this.el, {
tag: ‘input’,
type: ‘hidden’,
value: ‘false’,
name: this.getName()
}, true);
}
}
});