18 January 2008

Fun with ExtJS 2.0 Forms -- Radio Button Idiosyncrasies

As of late I've been working heavily with ExtJS 2.0's Form and Panel objects, and like I've said before, they're really cool. With ExtJS 2.0's new "component" system, you create form and page objects all at will, and just stick them wherever you want to -- the core Ext code takes care of the rest. It really is quite amazing, and shows the type of coding prowess that the ExtJS team have at their disposal.

That being said... nothing's perfect. :P The release is currently at "2.0", so that means, of course, that we're all awaiting a "2.1" to fix a few bugs here and there.

Ext.form.Radio, in particular, has quite a few little things that are "funny" with it -- namely, the fact that the "check" event only fires once, the very first time the radio button is checked... now, to those that know the HTML DOM, you may argue that this could in someway be the intended function, as all objects in a Radio input are essentially part of the same input object, and since a Radio object can't be "unchecked," that this is preferable behavior.

Well, whatever the actual intent was, one of the team members of Ext posted a fix here:
Ext.override(Ext.form.Radio, {
onClick : function() {
if(this.el.dom.checked != this.checked) {
var els = this.el.up('form').select('input[name='+this.el.dom.name+']');
els.each(function(el) {
if(el.dom.id == this.id) {
this.setValue(true);
} else {
Ext.getCmp(el.dom.id).setValue(false);
}
}, this);
}
}
});

Include this, and your "check" listener will now fire, and you can adjust things depending upon which choice is currently selected in the radio button. This was especially useful, since I've got some particular fieldsets that I want to stay hidden if the user doesn't need them (not just collapsed -- I've learned to just hide things completely, so that the wandering eyes of a user don't see something, even if it's optional...).

Also, when dealing with hide-whens and fields, in Ext 2.0, if you call "hide()" on a particular field, it doesn't hide the label as well. Jack Slocum himself actually posted a pretty good reason for this, but it's still somewhat counterintuitive, so someone posted a pretty good fix:

Ext.override(Ext.form.Field, {
showContainer: function() {
this.setVisible(true);
this.enable();
// show entire container and children (including label if applicable)
this.getEl().up('.x-form-item').setDisplayed(true);
},

hideContainer: function() {
this.disable(); // for validation
this.setVisible(false);
// hide container and children (including label if applicable)
this.getEl().up('.x-form-item').setDisplayed(false);
},

setContainerVisible: function(visible) {
if (visible) {
this.showContainer();
} else {
this.hideContainer();
}
return this;
}
});

Ext.form.Field.prototype.onRender =
Ext.form.Field.prototype.onRender.createSequence(function(config) {
if (this.hideContainerOnRender == true) {
this.hideContainer();
}
});

Now, instead of calling "hide()" on a field, just call "hideContainer()" and it'll do probably what you were wanting it to do. ;)

There's also some other issues with radio buttons, but I'm still researching if they're because of actual bugs or errant behavior, or because of my ignorance on the fundamental nature of radio inputs (namely, why if a radio button hasn't been selected or checked, that Ext.form.BasicForm.isValid() still returns true).

There's also a problem where, if you've got input fields inside fieldsets and you hide the fieldset without first hiding the input field, that the input field still tries to validate.

That make any sense? :P I've got a fix for that one, but I'll refrain from posting it just yet, because I'm almost sure that there's something that I'm missing.

1 comment:

  1. Anonymous2:41 AM

    Thanks! Great override. It fixed my 'hiding' problem.

    ReplyDelete