[RESOLVED] Everything in onsubmit handler is undefined!!!
Hi All;
I'm instantiating an object, then trying to use the function defined
within the object as a submit handler for the page/form. The handler
("val_obj.js_onsubmit_hndl") does indeed get called, but everything
in it is undefined - including the reference parameter to the event
object that should be passed when onsubmit is fired.
This is the most recent version of my code:
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
<script type="text/javascript"><!--
When the onsubmit runs, the scope in which the function is executed changes. This code might be easier to understand and maintain:
Code:
/**
* @class ActionControls
*
* Manages user interface controls and DOM events.
* @param object required Scope in which event handler functions are executed
* @param object required [handler name].[action] functions
* @return void
*/
function ActionControls(scope, eventHandlers) {
this.scope = scope;
this.eventHandlers = eventHandlers;
}
ActionControls.prototype = {
/**
* @property object Event handler functions
*/
eventHandlers : null,
/**
* @property object Scope in which event handler functions are executed
*/
scope : null,
/**
* Adds a user interface control.
* @param mixed required HTML tag Id or DOM node
* @param string required Event handler name, e.g. "onclick"
* @param string required Name of action performed
* @param array optional Array of arguments passed to event handler
* @return void
*/
addControl : function(id, handlerName, action, args) {
var node = (typeof(id) == "string") ? document.getElementById(id) : id;
if ( !node ) {
return;
}
if (!args) {
args = [];
}
args.unshift(node);
node[handlerName] = this.bind( this.scope, args, this.getEventHandler(handlerName, action) );
node = null;
},
/**
* Binds a function to a certain scope.
* @param object required Scope in which function executes
* @param array optional Array of arguments passed to bound function
* @param func required Function to be bound
* @return func Function closure that executes fn when executed.
*/
bind : function(scope, args, fn) {
if (!args) {
args = [];
}
return function(e) {
if (!e) {
e = window.event;
}
args.unshift(e);
return fn.apply(scope, args);
}
},
/**
* Class destructor to prevent memory leaks.
* @param void
* @return void
*/
destroy : function() {
this.eventHandlers = null;
this.scope = null;
},
/**
* Gets an event handler function.
* @param string required Event handler name
* @param string required Action performed
* @return func Function executed during an event.
*/
getEventHandler : function(handlerName, action) {
var fn = function() { alert(handlerName+"."+action+" is not a function."); };
var handlerObj = this.eventHandlers[handlerName];
if ( typeof(handlerObj) == "object") {
if ( typeof(handlerObj[action]) == "function" ) {
fn = handlerObj[action];
} else if ( typeof(handlerObj.defaultAction) == "function" ) {
fn = handlerObj.defaultAction;
}
}
handlerObj = null;
return fn;
}
};
function ValueAdder(val1, val2)
{
this.val1 = val1;
this.val2 = val2;
this.controls = new ActionControls(this, this.eventHandlers);
}
ValueAdder.prototype = {
controls : null,
val1 : 0,
val2 : 0,
eventHandlers : {
onsubmit : {
calculate : function(e, el) {
var total = this.val1 + this.val2;
alert( "The calculated value is: " + total );
return false;
}
}
},
addControlSubmit : function(id) {
this.controls.addControl(id, "onsubmit", "calculate");
}
};
var myAdder = new ValueAdder(3, 2);
myAdder.addControlSubmit("form_id_here");
The ActionControls class takes care of all the mess. It provides a bridge between the onsubmit event handler and the instance of the ValueAdder class. In your code, the "this" keyword in the onsubmit actually points to the <form> tag, not an instance of the "the_obj_def" class.
I called my class "ValueAdder" instead of "the_obj_def" because, in this case, "ValueAdder" is more descriptive of what the class does.
Not really. Using the ActionControls class is about as simple as it gets. Your class definition needs a property called "controls" which is an instance of the ActionControls class. Then create a method in your class for each control you want to create. Here is a stripped down example of how to use this programming pattern:
You don't really need to bother with exactly how the ActionControls class works. It allows you to go about solving the problem that the class is supposed to solve, rather than worry about assigning event handlers. Furthermore, it allows you to write event handler code in a more structured and maintainable way, with all event handler functions going in a class's eventHandlers property. The event handlers are then broken down further by the event handler name (e.g. "onclick", "onmouseover", etc), with the actual event handler functions inside that.
Say 8 months from now you go back to a class you wrote utilizing this programming pattern. You need to add some functionality to an onclick of a button. You know all the event handler functions are located in the eventHandlers property. Inside that is a property called "onclick" which houses all the onclick event handlers. The button you want to change is the Cancel button, so you know you need to edit the eventHandlers.onclick.cancel function. Makes it super easy to come back to your code later and pick up where you left off, instead of sifting through many lines of code looking for where you assigned an onclick event handler.
It also provides the client code utilizing your class an easy interface for assigning event handlers.
Code:
var x = new MyClass();
x.addControlSubmit("form_id");
x.addControlCancel("button_id");
Of course, if you do want to know how the ActionControls class works, I'd be more than happy to oblige.
> Not really. Using the ActionControls class is about as simple as it gets.
The thing that I neglected to tell you is that I'm operating under ASP.NET,
and generating the Javascript dynamically from the server. I need for the
script to be as short and sweet as possible.
THIS is what I needed to know - and it put me on the right track:
> In your code, the "this" keyword in the onsubmit actually points to
> the <form> tag, not an instance of the "the_obj_def" class.
THANKS!!!
Keep in mind that - in Javascript - a person can add objects to other
objects at any time, at any point, and for any reason. Once I realized
what "this" is referring to, it was a simple matter to just add the submit
object ("the_obj_def") to the form object, and then make the proper
references within the handler accordingly.
This is the script that worked:
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Bookmarks