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 replace
d 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?
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(f) {
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>
EDIT : missing parameter f in function testOnsubmitAndSubmit
The above should work regardless of whether you assign the onsubmit
HTML attribute or assign it in JavaScript:
document.forms['theForm'].onsubmit = onsubmitHandler;
Try
if (this.onsubmit instanceof Function) {
// do stuff;
}
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
What browser are you using?
alert(typeof document.getElementById('myform').onsubmit);
This gives me "function
" in IE7 and FireFox.
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"
using a string based variable as example and making use instanceof Function
You register the function..assign the variable...check the variable is the name of function...do pre-process... assign the function to new var...then call the function.
function callMe(){
alert('You rang?');
}
var value = 'callMe';
if (window[value] instanceof Function) {
// do pre-process stuff
// FYI the function has not actually been called yet
console.log('callable function');
//now call function
var fn = window[value];
fn();
}
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.');
}
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.
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
}
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!");
}
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").prop("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()
if ( window.onsubmit ) {
//
} else {
alert("Function does not exist.");
}
You can always use one of the typeOf functions on JavaScript blogs such as Chris West's. Using a definition such as the following for the typeOf()
function would work:
function typeOf(o){return {}.toString.call(o).slice(8,-1)}
This function (which is declared in the global namespace, can be used like this:
alert("onsubmit is a " + typeOf(elem.onsubmit));
If it is a function, "Function" will be returned. If it is a string, "String" will be returned. Other possible values are shown here.
// This should be a function, because in certain JavaScript engines (V8, for
// example, try block kills many optimizations).
function isFunction(func) {
// For some reason, function constructor doesn't accept anonymous functions.
// Also, this check finds callable objects that aren't function (such as,
// regular expressions in old WebKit versions), as according to EcmaScript
// specification, any callable object should have typeof set to function.
if (typeof func === 'function')
return true
// If the function isn't a string, it's probably good idea to return false,
// as eval cannot process values that aren't strings.
if (typeof func !== 'string')
return false
// So, the value is a string. Try creating a function, in order to detect
// syntax error.
try {
// Create a function with string func, in order to detect whatever it's
// an actual function. Unlike examples with eval, it should be actually
// safe to use with any string (provided you don't call returned value).
Function(func)
return true
}
catch (e) {
// While usually only SyntaxError could be thrown (unless somebody
// modified definition of something used in this function, like
// SyntaxError or Function, it's better to prepare for unexpected.
if (!(e instanceof SyntaxError)) {
throw e
}
return false
}
}
A simple check like this will let you know if it exists/defined:
if (this.onsubmit)
{
// do stuff;
}
来源:https://stackoverflow.com/questions/798340/testing-if-value-is-a-function