views:

4508

answers:

4

I have a case where I have a bunch of text boxes and radio buttons on a screen all built dynamically with various DIVs. There are onblur routines for all of the text boxes to validate entry, but depending on the radio button selection, the text box entry could be invalid when it was valid originally. I can't use onblur with the radio buttons because they could go from the radio button into one of the text boxes that was made invalid and create an infinite loop since I'm putting focus into the invalid element. Since each text box has its own special parameters for the onblur calls, I figure the best way to do this is to call the onblur event for the textboxes when the form gets submitted to make sure all entry is still valid with the radio button configuration they have selected. I also need it to stop submitting if one of the onblur events returns false so they can correct the textbox that is wrong. This is what I've written...

    for (var intElement = 0; intElement < document.forms[0].elements.length; intElement = intElement + 1)
    {
        if (document.forms[0].elements[intElement].name.substr(3) == "FactorAmount") // The first 3 characters of the name are a unique identifier for each field
        {
            if (document.forms[0].elements[intElement].onblur())
            {
                return false;
                break;
            }
        }
    }

return true;

I originally had (!document.forms[0].elements[intElement].onblur()) but the alert messages from the onblur events weren't popping up when I had that. Now the alert messages are popping up, but it's still continuing to loop through elements if it hits an error. I've stepped through this with a debugger both ways, and it appears to be looping just fine, but it's either 1) not stopping and returning false when I need it to or 2) not executing my alert messages to tell the user what the error was. Can someone possibly help? It's probably something stupid I'm doing.

The onblur method that is getting called looks like this...

function f_VerifyRange(tagFactor, reaMin, reaMax, intPrecision, sLOB, sIL, sFactorCode)
{
    var tagCreditOrDebit;
    var tagIsTotal;
    var tagPercentageOrDecimal;

    eval("tagCreditOrDebit = document.forms[0]." + tagFactor.name.substr(0,3) + "CreditOrDebitC");

    eval("tagIsTotal = document.forms[0]." + tagFactor.name.substr(0,3) + "IsTotal");
    eval("tagPercentageOrDecimal = document.forms[0]." + tagFactor.name.substr(0,3) + "PercentageOrDecimal");

    if (tagPercentageOrDecimal.value == "P")
    {
        reaMax = Math.round((reaMax - 1) * 100);
        reaMin = Math.round((1 - reaMin) * 100);

        if (parseFloat(tagFactor.value) == 0)
        {
         alert("Please enter a value other than 0 or leave this field blank.");

            f_SetFocus(tagFactor);
         return false;
        }

        if (tagIsTotal.value == "True")
        {
            if (tagCreditOrDebit.checked)
            {
                if (parseFloat(tagFactor.value) > reaMin)
                {
                 alert("Please enter a value less than or equal to " + reaMin + "% for a credit or " + reaMax + "% for a debit.");
                    f_SetFocus(tagFactor);
                 return false;
                }
            }
            else
            {
                if (parseFloat(tagFactor.value) > reaMax)
                {
                 alert("Please enter a value less than or equal to " + reaMin + "% for a credit or " + reaMax + "% for a debit.");
                    f_SetFocus(tagFactor);
                 return false;
                }
            }
        }
    }

    return true;
}

EDIT: I think I've figured out why this isn't working as expected, but I still don't know how I can accomplish what I need to. The line below...

            if (!document.forms[0].elements[intElement].onblur())

or

            if (document.forms[0].elements[intElement].onblur())

is not returning what the single onblur function (f_VerifyRange) is returning. Instead it is always returning either true or false no matter what. In the first case, it returns true and then quits and aborts the submit after the first textbox even though there was no error with the first textbox. In the second case, it returns false and runs through all the boxes. Even though there might have been errors (which it displays), it doesn't think there are any errors, so it continues on with the submit. I guess what I really need is how to get the return value from f_VerifyRange which is my onblur function.

A: 

First, for the love of god and all that is holy, stop writing native javascript and help yourself to some of that jQuery :)

Second, start using a validation framework. For jQuery, jQuery Validate usually works really well. It supports things like dependencies between different fields, etc. And you can also quite easily add new rules, like valid ISBN numbers, etc.

Edit: As for your code, I'm not sure that you can use onunload for this, as at that point there's no way back, you can't abort at that point. You should put this code on the onsubmit event instead.

Erlend Halvorsen
I would love to switch tools, honestly, and I will forward this on to my boss in hopes that someday we will not be doing this, but being that developers at my company don't have a lot of freedom to install whatever we want on our machines, this is really not an option. Thanks for the suggestion!
You have my deepest sympathy, writing plain javascript just outright sucks!
Erlend Halvorsen
I guess I should clarify that the code is not being run onunload. It's being run onbeforeunload. I'm not sure if onsubmit will fix the problem, but I could try it.
@Julie: Perhaps you can get your boss to loosen up about implementing jQuery, given the fact that big companies like Google and Bank of America uses the framework, and the fact that Microsoft will be incorporate it in Website projects in Visual Studio some time soon...?
roosteronacid
It sounds like something we might be able to switch to when we convert to .NET hopefully next year. Yes, we are still using Visual Studio 6. Implementation will probably happen eventually, but it will probably take longer than 1 week which is the time I have to finish this project.
I still think you wont be able to cancel the unload, as that would enable spamers to lock you on a specific site and render your browser window unusable..
Erlend Halvorsen
Okay, I've got the code running onsubmit now. The browser unfortunately still does not give them a chance to correct anything. I may have to handle this some other way such as disabling radio buttons that aren't valid for the entry they put in the textbox.
+1  A: 

This question is a bit too involved for me at this time of the night, but I will give you this bit of advice:

eval("tagCreditOrDebit = document.forms[0]." + tagFactor.name.substr(0,3) + "CreditOrDebitC");

This can be written in a MUCH better way:

tagCreditOrDebit = document.forms[0][tagFactor.name.substr(0,3) + "CreditOrDebitC"];

In javascript, anywhere where you can use dotted syntax, you can use square brackets.

document.body;
document['body'];
var b = 'body';
document[b];

Also, think about giving your forms some sort of identifier. I have no clue at all why document.forms[0] was the standard way to address a form for so long... if you decide to place another form on the page before this one, then everything will break!

Other ways to do it include:

// HTML
<form name="myFormName">

// Javascript
var f = document.myFormName;

or

<form id="myFormId">

var f = document.getElementById("myFormId")
nickf
The square brackets are a great suggestion, and something I will definitely implement! Naming the form is something I'm really not too concerned about because we never have more than one form on a webpage here, but I do see your point.
A: 

I ended up solving this with a global variable. I originally set a value g_bHardEditsPassed to true assuming we will have no errors. Then in f_VerifyRange, everytime I return a value, I put a line before it to set the g_bHardEditsPassed variable to match. Then I modified the loop to look like this...

    g_bHardEditsPassed = true;

    for (var intElement = 0; intElement < document.forms[0].elements.length; intElement = intElement + 1)
    {
        if (document.forms[0].elements[intElement].name.substr(3) == "FactorAmount")
        {
            document.forms[0].elements[intElement].onblur()
            if (!g_bHardEditsPassed)
            {
                g_bHardEditsPassed = true;
                return false;
            }
        }
    }

    return true;

Thanks for everyone's suggestions. I'm sure that the jQuery thing especially will be worth looking into for the future.

you got a bug there in your hungarian notation.
nickf
@nickf: You're absolutely right. The one line I didn't copy and paste because I didn't grab it when I was highlighting, and I make an error in it. :) Fixed.
A: 

You´re not getting any success with if (!...onblur()) because the return of onblur() is always undefined when used directly. OnBlur() is a Event Handler Function. Like you descovered, you have to create a workaround.

Leonel Martins