PDA

View Full Version : Get invalid fields from tabbed form



hallikpapa
7 Oct 2009, 6:20 PM
I am doing a lot of validation on submit, and if form.isValid() fails, it pops up an error to fix everything marked invalid, and labels the invalid fields correctly. This is all in one form, but the form is split between 3 tabs. I have an iconCls set in each tab label, hidden. But I am looking for a way to find out what all fields that were in invalid, and enable the iconCls to visually cue the user they need to check that tab too.

Is there some function I can call to find out which tabs have invalid fields, or the invalid tabs, so I know which iconCls(s) to enable?

I see there is form.getValues(), but it returns an key->val pair but thought there might be a way to view invalid fields by tab.

Or any tips to point me in the right direction?

mitchellsimoens
7 Oct 2009, 6:27 PM
just to get something working I'd create an array for each tab and then go through each invalid field to match each array and that'll tell you which tab then would have invalid fields.

this would get you a proof of concept until something else comes through.

hallikpapa
7 Oct 2009, 6:45 PM
I will give that a shot. I might also add that I have overridden a FormPanel, and trying to use an overridden markInvalid function, put a breakpoint in firebug, but it is never hit.

When I break on form.markInvalid(), I see that the xtype is the correct tabbedform name I gave it, but it goes to the ext-all-debug.js version of markInvalid, not mine...




Ext.ux.TabbedForm = Ext.extend(Ext.form.FormPanel, {
...
....
....
...
,markInvalid : function(msg){
Ext.ux.TabbedForm.superclass.markInvalid.apply(this, arguments);
if(!this.rendered || this.preventMark){ //BREAK POINT HERE NEVER REACHED ON A FAILED FORM
return;
}
....
....
....
this.fireEvent('invalid', this, msg);
}

<edit> I was doing Ext.getCmp('user-details-form').getForm().markInvalid() instead of just Ext.getCmp('user-details-form').markInvalid(). Now I am the function, and will continue to work through this. Thank you for the pointers so far!

hallikpapa
7 Oct 2009, 8:00 PM
From googling and tinkering around, I accomplished my goal by putting the isValid and markInvalid functions in my extended formPanel.

Here is what made the tabs flash a red box around the each tab label for each invalid field.


, isValid : function(){
var valid = true;
this.getForm().items.each(function(f){
if(!f.validate()){
valid = false;
Ext.getCmp('user-details-form').markInvalid(f);
}
});
return valid;
},

markInvalid : function(msg){
if(!this.rendered || this.preventMark){
return;
}
this.el.addClass(this.invalidClass);
msg = msg || this.invalidText;
var pp;
var tp = msg.findParentBy(function(p, c){
if(p.isXType('tabpanel')){
return true;
}
pp = p;
});
if(!Ext.isEmpty(pp,false) && !Ext.isEmpty(tp,false)){
var e = tp.getTabEl(pp);
if(!Ext.isEmpty(e)) {
Ext.fly(e).frame("ff0000");
}
}
this.fireEvent('invalid', this, msg);
}

Animal
7 Oct 2009, 11:12 PM
I do a similar thing.

Find the invalid fields.



Ext.override(Ext.form.BasicForm, {
findInvalid: function() {
var result = [], it = this.items.items, l = it.length, i, f;
for (i = 0; i < l; i++) {
if(!(f = it[i]).disabled && f.el.hasClass(f.invalidClass)){
result.push(f);
}
}
return result;
}
});


You can then ensure that the first one is visible, and call frame("red") on it.

Thee following ensures that a Component is visible by walking up its ownerCt chain and activating any parent Container. It also scrolls if needed:



Ext.override(Ext.Component, {
ensureVisible: function(stopAt) {
var p;
this.ownerCt.bubble(function(c) {
if (p = c.ownerCt) {
if (p instanceof Ext.TabPanel) {
p.setActiveTab(c);
} else if (p.layout.setActiveItem) {
p.layout.setActiveItem(c);
}
}
return (c !== stopAt);
});
this.el.scrollIntoView(this.el.up(':scrollable'));
return this;
}
});


The scrollable pseudo class so we can find the nearest scrollable parent element:



Ext.DomQuery.pseudos.scrollable = function(c, t) {
var r = [], ri = -1;
for(var i = 0, ci; ci = c[i]; i++){
var o = ci.style.overflow;
if(o=='auto'||o=='scroll') {
if (ci.scrollHeight < Ext.fly(ci).getHeight(true)) r[++ri] = ci;
}
}
return r;
};


so you can just use



var f = myBasicForm.findInvalid()[0];
if (f) {
f.ensureVisible().frame("red");
}

steffenk
23 Mar 2010, 4:25 PM
Thanks Animal for sharing this! I like the ensureVisible function.

steffenk
23 Mar 2010, 4:45 PM
no, why should it? Explore your code, you have an error in.

Animal
24 Mar 2010, 12:28 AM
You have to learn to stand on your own two feet and operate in the jaavscript+browser environment.

Just dumping something about "an error about .el" on a forum will not see you through your working day.

These are just programming problems which are part of your job to find using the tools available. You can break on that error, and find what is wrong.

hAmpzter
12 Apr 2010, 3:10 PM
I do a similar thing.

Find the invalid fields.
...



You are just wonderful Animal! ;)
Thank you a million!

Regards,
hAmpzter

obbakilla
1 May 2010, 5:09 AM
@animal: thanks for the fancy solution!
@ExtKD: this behaviour occurs when you haven't opened every tab (with form elements) before submitting the form. (hint: deferredRenderer etc). a possible solution could be to use the (undocumented) boxReady. Here is the changed code for the finder-function:

Ext.override(Ext.form.BasicForm, {
findInvalid: function() {
var result = [], it = this.items.items, l = it.length, i, f;
for (i = 0; i < l; i++) {
if(!(f = it[i]).disabled && f.boxReady) {
if(f.el.hasClass(f.invalidClass)){
result.push(f);
}
}
}
return result;
}
});

maybe not the best solution, but a solution ;)

completej
21 May 2010, 7:18 AM
Dumb question, but how are you using that override / boxReady where the form is invalid due to not opening every tab? (edit: I included animal's overrides and replaced it with your mod, but due to the form type mentioned below, the error of the form being invalid still exists)

I have a 5 tab form, and values are required on Tabs 1, 3, and 5. This form is part of a multi-step process. Initially, all required fields are filled out as the user is forced to go through all the tabs to enter their information, so the form is always valid.

The next step requires a user to authorize the form to move it to the third step. They open the form from a grid / list, and Tab 1 is opened. This user only is required to stap an ID to show they have authorized the form, so they are not "required" to open tabs 3 and 5 to move the form to its next step (ideally, they should, to verify all the information is correct, but I digress...).

The user, without opening Tabs 3 and 5, submits the form, but gets my default message when a form is invalid. Once they open those tabs, the form then submits without fail.

Having trouble coming up with a solution to render those tabs after form load and before the validation / submit. Suggestions? Thanks,

edit2: Was it as simple as setting the tab panel to deferredRender: false? and if so, does that not re-introduce any type of slowdown due to rendering?

edit3: this thread is exactly what i am describing as well
http://www.extjs.com/forum/showthread.php?97942-How-to-mark-invalid-a-non-rendered-field

devtig
19 Feb 2013, 12:35 PM
I got a ExtJS 4 version of Animal's findInvalid


Ext.form.Basic.prototype.findInvalid = function() {
var me = this,
invalid;
Ext.suspendLayouts();
invalid = me.getFields().filterBy(function(field) {
var preventMark = field.preventMark, isValid;
field.preventMark = true;
isValid = field.validate();
field.preventMark = preventMark;
return !isValid;
});
Ext.resumeLayouts(true);
return invalid;
};