[CLOSED] cross-window form validation with focus on an invalid control

  1. #1

    [CLOSED] cross-window form validation with focus on an invalid control

    I have two windows:
    - 1 that contains the ext form and its controls
    - 1 that contains the action buttons, particularly 'Save'

    Step to reproduce:
    - enter something invalid in a combobox of the form
    - click on 'save'

    The combobox doesn't receive any 'blur' event and the validation passes.

    I'm looking for a generic solution that would work for a form with any kind of ext controls in it.

    My current best solution is to manually trigger a 'mousedown' event on the ext form.
    Unfortunately, a delay is set in mousedown event handler in Ext.form.TriggerField.onFocus API:
    this.doc.on('mousedown', this.mimicBlur, this, {delay: 10});
    So it works only if I also put a timer (above 10) between the mousedown generated and the validation check.

    Is there a better way to do it?
    Is it possible to avoid the timer and asynchronous validation?

    Form window:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Form Validation from a different window</title>
        <script language="javascript" type="text/javascript">
            function isFormValid()
            {
                return frmMain.getForm().isValid();
            }
        </script>
    </head>
    
    <body>
        <div>
        <b>Validation passed although a field is invalid</b>
        <ul>
            <li>Enter something invalid in the combobox</li>
            <li>Click Save</li>
        </ul>
        <form id="Form1" runat="server">
            <ext:ResourceManager ID="ResourceManager1" runat="server" />
            <ext:FormPanel ID="frmMain" runat="server">
                <Items>
                    <ext:ComboBox ID='cb1' runat="server" AllowBlank="false" Text="first" >
                        <Items>
                            <ext:ListItem Text="aaa" Value="a" />
                            <ext:ListItem Text="bbb" Value="b" />
                            <ext:ListItem Text="ccc" Value="c" />
                            <ext:ListItem Text="ddd" Value="d" />
                            <ext:ListItem Text="eee" Value="e" />
                        </Items>
                    </ext:ComboBox>
                    <ext:ComboBox ID='cb2' runat="server" AllowBlank="false"  Text="second">
                        <Items>
                            <ext:ListItem Text="aaa" Value="a" />
                            <ext:ListItem Text="bbb" Value="b" />
                            <ext:ListItem Text="ccc" Value="c" />
                            <ext:ListItem Text="ddd" Value="d" />
                            <ext:ListItem Text="eee" Value="e" />
                        </Items>
                    </ext:ComboBox>
                </Items>
            </ext:FormPanel>
        </form>
        <br />
        Save Button is in another window:<br />
        <iframe src="testbtn.aspx" height="50" width="100"></iframe>
        </div>
    </body>
    </html>
    Buttons window:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
        <script language="javascript" type="text/javascript">
            function clickSave()
            {
                // Is there a better way to do it without having to generate a onmousedown
                // and performs an aynchrounous validation ?
                window.parent.document.body.fireEvent('onmousedown');
                window.setTimeout(check, 20);
                
            }
            function check()
            {
                alert(window.parent.isFormValid() ? "Form valid -> save OK" : "Form invalid-> save KO");
            }
        </script>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <ext:ResourceManager ID="ResourceManager1" runat="server" />
            <ext:FormPanel ID="frmBtn" runat="server">
                <Items>
                    <ext:Button ID='btnSave' Text="Save" runat="server" OnClientClick="clickSave()"></ext:Button>
                </Items>
            </ext:FormPanel>
        </div>
        </form>
    </body>
    </html>
    Click image for larger version. 

Name:	FormValid.png 
Views:	109 
Size:	24.5 KB 
ID:	3087

    Thanks
    Last edited by geoffrey.mcgill; Aug 23, 2011 at 7:30 PM. Reason: [CLOSED]
  2. #2
    Hi,

    The problem is the fact that any events are not bubbled through iframes.

    So, the ComboBox's Blur event is not fired when you click on the Save button.

    I can suggest you to manually trigger blur for a focused field before validating.
    function isFormValid()
    {
        frmMain.items.each(function (item) {
            if (item.hasFocus) {
                item.blur && item.blur();
                item.triggerBlur && item.triggerBlur();
            }
        });
        return frmMain.getForm().isValid();
    }
  3. #3
    Thanks Daniil.
    I will go with your solution that I have incorporated in the isValid form method to avoid to change existing code.
    I also had to recursively look into form fields as the hasFocus can be any level deeps behind some containers.
    For better perf, I also stop the search for focus control after I found it.

    Here is the result:
    Ext.form.BasicForm.override({
    	isValid: function ()
    	{
    		var valid = true;
    		removeContainerFocus(this.items); // Remove current focus
    		this.items.each(function (item)
    		{
    			if (item.isVisible() && !item.validate()) // Don't validate hidden fields
    				valid = false;
    		});
    		return valid;
    	}
    });
    
    // Recursive function that remove focus to any control contained in the collection argument
    function removeContainerFocus(mixCollect)
    {
    	for (var i = 0, items = mixCollect.items, len = items.length; i < len; i++)
    	{
    		var item = items[i];
    		if (item.hasFocus)
    		{
    			if (item.blur) item.blur();
    			if (item.triggerBlur) item.triggerBlur();
    			return true;
    		}
    		else if (item.items && (item.items.length > 0) && removeContainerFocus(item.items))
    			return true;
    	}
    	return false;
    }
    By the way, why do you copy the items in function each of Ext.util.MixedCollection?
    each : function(fn, scope){
           var items = [].concat(this.items);
           for(var i = 0, len = items.length; i < len; i++){
    Thx
  4. #4
    Thanks for sharing the code, it can help someone in the future.

    Quote Originally Posted by ViniVidi View Post
    By the way, why do you copy the items in function each of Ext.util.MixedCollection?
    each : function(fn, scope){
           var items = [].concat(this.items);
           for(var i = 0, len = items.length; i < len; i++){
    Please follow the link:
    http://dev.sencha.com/deploy/ext-3.4...ollection-each

    I see:
    each : function(fn, scope){ 
           var items = [].concat(this.items); // each safe for removal

Similar Threads

  1. Replies: 4
    Last Post: Apr 30, 2012, 4:49 PM
  2. Replies: 3
    Last Post: Oct 04, 2011, 8:30 AM
  3. [CLOSED] Remote validation - untouched control flagged as invalid
    By daneel in forum 1.x Legacy Premium Help
    Replies: 11
    Last Post: Mar 10, 2011, 3:57 PM
  4. Replies: 2
    Last Post: Feb 12, 2010, 5:03 AM
  5. [CLOSED] Form Validation within template of a asp:login control
    By ljcorreia in forum 1.x Legacy Premium Help
    Replies: 5
    Last Post: Nov 27, 2009, 12:15 PM

Tags for this Thread

Posting Permissions