views:

2842

answers:

13

I need to test whether the value of a form's onsubmit is a function. The format is typically onsubmit="return valid();". Is there a way to tell if this is a function, and if it's callable? Using typeof just returns that it's a string, which doesn't help me much.

EDIT: Of course, I understand that "return valid();" is a string. I've replaced it down to "valid();", and even "valid()". I want to know if either of those is a function.

EDIT: Here's some code, which may help explain my problem:

$("a.button").parents("form").submit(function() {
    var submit_function = $("a.button").parents("form").attr("onsubmit");
    if ( submit_function && typeof( submit_function.replace(/return /,"") ) == 'function' ) {
        return eval(submit_function.replace(/return /,""));
    } else {
        alert("onSubmit is not a function.\n\nIs the script included?"); return false;
    }
} );

EDIT 2: Here's the new code. It seems that I still have to use an eval, because calling form.submit() doesn't fire existing onsubmits.

var formObj = $("a.button").parents("form");
formObj.submit(function() {
    if ( formObj[0].onsubmit && typeof( formObj.onsubmit ) == 'function' ) {
        return eval(formObj.attr("onsubmit").replace(/return /,""));
    } else {
        alert("onSubmit is not a function.\n\nIs the script included?");
        return false;
    }
} );

Suggestions on possibly how to do this better?

A: 

A simple check like this will let you know if it exists/defined:

if (this.onsubmit)
{
  // do stuff;
}
Kon
This won't work. The if will assert to TRUE when onsubmit is a non-empty string as well.
Seb
A horrible way of testing if something is a function - as indicated, and to be clearer: anything "truthy" would cause this code to "do stuff" and that might not be what is expected. If this.onsubmit were set to the value of 5 or "hello" or anything else in JavaScript that evaluates to true, you are going to get unexpected behavior.
Jason Bunting
The subject of the question asks how to check if something exists. That's all I was suggesting - no more, no less.
Kon
Not really - the original posted states that he has the "need to test whether the value of a form's onsubmit is a function." Your condition isn't whether or not this.onsubmit is a funciton, your test simply asks whether or not this.onsubmit is "truthy"
Jason Bunting
+2  A: 

Make sure you are calling typeof on the actual function, not a string literal:

function x() { 
    console.log("hi"); 
}

typeof "x"; // returns "string"

typeof x; // returns "function"
matt b
+3  A: 

What browser are you using?

alert(typeof document.getElementById('myform').onsubmit);

This gives me "function" in IE7 and FireFox.

Greg
Even if your onsubmit is "return valid();"?
gms8994
Yes - don't forget, you can't have "return" outside a function.
Greg
form.onsubmit will always be a function as long as it's defined as an HTML attribute. See my answer.
Ionuț G. Stan
+2  A: 

You can try modifying this technique to suit your needs:

function isFunction() {
    var functionName = window.prompt('Function name: ');
    var isDefined = eval('(typeof ' + functionName + '==\'function\');');
    if (isDefined)
        eval(functionName+'();');
    else
        alert('Function ' + functionName + ' does not exist');
}

function anotherFunction() {
    alert('message from another function.');
}
cletus
+10  A: 

Try

if (this.onsubmit instanceof Function) {
    // do stuff;
}
artemb
That "this" is dangerous. Where should that code reside?
Ionuț G. Stan
that's just a sample. You can change it to button.onsubmit instanceof Function
artemb
+1  A: 

Well, "return valid();" is a string, so that's correct.

If you want to check if it has a function attached instead, you could try this:

formId.onsubmit = function (){ /* */ }

if(typeof formId.onsubmit == "function"){
  alert("it's a function!");
}
Seb
+1  A: 

If it's a string, you could assume / hope it's always of the form

return SomeFunction(arguments);

parse for the function name, and then see if that function is defined using

if (window[functionName]) { 
    // do stuff
}
Sii
+1  A: 
  if ( window.onsubmit ) 
  {
   //
  } else {
     alert("Function does not exist.");
  }
TStamper
+3  A: 

You could simply use the typeof operator along with a ternary operator for short:

onsubmit="return typeof valid =='function' ? valid() : true;"

If it is a function we call it and return it's return value, otherwise just return true

Edit:

I'm not quite sure what you really want to do, but I'll try to explain what might be happening.

When you declare your onsubmit code within your html, it gets turned into a function and thus its callable from the JavaScript "world". That means that those two methods are equivalent:

HTML: <form onsubmit="return valid();" />
JavaScript: myForm.onsubmit = function() { return valid(); };

These two will be both functions and both will be callable. You can test any of those using the typeof operator which should yeld the same result: "function".

Now if you assign a string to the "onsubmit" property via JavaScript, it will remain a string, hence not callable. Notice that if you apply the typeof operator against it, you'll get "string" instead of "function".

I hope this might clarify a few things. Then again, if you want to know if such property (or any identifier for the matter) is a function and callable, the typeof operator should do the trick. Although I'm not sure if it works properly across multiple frames.

Cheers

Pablo Cabrera
I need to test this outside of the onsubmit though.
gms8994
+1  A: 

What are you trying to accomplish with this? Are you trying to stop the onsubmit, are you trying to manipulate the action that occurs onsubmit or is there some other goal?

iKnowKungFoo
I'm replacing a submit button with an anchor link. Since calling form.submit() does not activate onsubmit's, I'm finding it, and eval()ing it myself. But I'd like to check if the function exists before just eval()ing what's there.
gms8994
+2  A: 

form.onsubmit will always be a function when defined as an attribute of HTML the form element. It's some sort of anonymous function attached to an HTML element, which has the this pointer bound to that FORM element and also has a parameter named event which will contain data about the submit event.

Under these circumstances I don't understand how you got a string as a result of a typeof operation. You should give more details, better some code.

Edit (as a response to your second edit):

I believe the handler attached to the HTML attribute will execute regardless of the above code. Further more, you could try to stop it somehow, but, it appears that FF 3, IE 8, Chrome 2 and Opera 9 are executing the HTML attribute handler in the first place and then the one attached (I didn't tested with jQuery though, but with addEventListener and attachEvent). So... what are you trying to accomplish exactly?

By the way, your code isn't working because your regular expression will extract the string "valid();", which is definitely not a function.

Ionuț G. Stan
+1  A: 

I think the source of confusion is the distinction between a node's attribute and the corresponding property.

You're using:

$("a.button").parents("form").attr("onsubmit")

You're directly reading the onsubmit attribute's value (which must be a string). Instead, you should access the onsubmit property of the node:

$("a.button").parents("form").onsubmit

Here's a quick test:

<form id="form1" action="foo1.htm" onsubmit="return valid()"></form>
<script>
window.onload = function () {
    var form1 = document.getElementById("form1");

    function log(s) {
        document.write("<div>" + s + "</div>");
    }

    function info(v) {
        return "(" + typeof v + ") " + v;
    }

    log("form1 onsubmit property: " + info(form1.onsubmit));
    log("form1 onsubmit attribute: " + info(form1.getAttribute("onsubmit")));
};
</script>

This yields:

form1 onsubmit property: (function) function onsubmit(event) { return valid(); }
form1 onsubmit attribute: (string) return valid()
Ates Goral
+2  A: 

I'm replacing a submit button with an anchor link. Since calling form.submit() does not activate onsubmit's, I'm finding it, and eval()ing it myself. But I'd like to check if the function exists before just eval()ing what's there. – gms8994

<script type="text/javascript">
function onsubmitHandler() {
    alert('running onsubmit handler');
    return true;
}
function testOnsubmitAndSubmit() {
    if (typeof f.onsubmit === 'function') {
        // onsubmit is executable, test the return value
        if (f.onsubmit()) {
            // onsubmit returns true, submit the form
            f.submit();
        }
    }
}
</script>

<form name="theForm" onsubmit="return onsubmitHandler();">
<a href="#" onclick="
    testOnsubmitAndSubmit(document.forms['theForm']);
    return false;
"></a>
</form>

The above should work regardless of whether you assign the onsubmit HTML attribute or assign it in JavaScript:

document.forms['theForm'].onsubmit = onsubmitHandler;
Grant Wagner
where does f in f.onsubmit come from?
Art