Handling Forms
Unique Identifiers
Accessing and controlling forms is best achieved by placing a unique identifier on the form element, so that from there you can use the form’s elements collection to access all of the form fields within that form.
Do not use a name attribute to identify the form. That is a technique from the previous century that died out along with using named anchors. Name attributes should only be used to identify fields within a form that are to be submitted.
Use an id attribute to provide a unique identifier for the form:
<form id="mariachiBand">
<p><label>
<input type="checkbox" name="mariachi">
Allow Mariachi band to interrupt our meal?
</label></p>
<p><input type="submit"></p>
</form>
There is no requirement to place unique identifiers on the individual form fields. The form contains a collection called elements, which contains all of the form fields.
Associating Events
Once the form exists, use scripting to attach events on to either the form itself, or on to elements of the form. This can be best achieved by putting your script at the end of the body, just before the </body> tag.
<html>
<head>
...
</head>
<body>
...
<script src="script.js"></script>
</body>
</html>
The scripting can then easily retrieve a reference to the form element, and uses that to associate functions to the events of the form, or to elements of the form.
var form = document.getElementById('mariachiBand');
form.onsubmit = ...
Attaching Functions
Both anonymous functions and named functions can be attached to events.
This is an anonymous function being attached to the onsubmit event of the form:
form.onsubmit = function () {
var form = this;
if (form.elements.mariachi.checked) {
return confirm('Are you absolutely certain that you want a Mariachi band?'); // prevent form submission if need be
}
};
When attaching named events, it is only the name of the function that you use. Do not use the parenthesis after the name as that will invoke the function, causing only the returned value from the function to be assigned.
function mariachiHandler() {
var checkbox = this,
bandname = this.bandname;
if (!checkbox.checked) {
return alert(bandname + ' regret your decision.');
}
}
var mariachi = form.elements.mariachi;
mariachi.bandName = 'The Broken Strings';
mariachi.onclick = mariachiHandler;
Issues with Parameters
When passing parameters to the functions, don’t try to pass the parameters directly since that will only result in the returned value from the function being assigned.
var mariachi = form.elements.mariachi;
mariachi.onclick = mariachiHandler('Broken Strings'); // problem: no function is assigned to the event.
// Only the returned value from the function is assigned, resulting in the event doing nothing.
You can create a function directly, and from inside of that function invoke your function with its parameters, but you need to then pay special attention to the this keyword:
function mariachiHandler(bandname) {
...
}
var mariachi = form.elements.mariachi;
mariachi.onclick = function () {
return mariachiHandler('Broken Strings'); // problem: the this keyword is not retained in the function call
};
Retaining Context to the Function
So to retain the this keyword while also passing parameters to the function, you can use the .call() method to invoke the function from within the correct context.
function mariachiHandler(bandname) {
...
}
var mariachi = form.elements.mariachi;
mariachi.onclick = function () {
return mariachiHandler.call(this, 'Broken Strings');
};
You can also automate this by creating a function that does much of the dirty work for you, where the .apply() method is used to pass a context and parameters to a function.
function mariachiHandler(bandname) {
var checkbox = this;
if (!checkbox.checked) {
return alert(bandname + ' regret your decision.');
}
}
function paramsToHandler(handler, params) {
return function () {
handler.apply(this, params);
};
}
var mariachi = form.elements.mariachi;
mariachi.onclick = paramsToHandler(mariachiHandler, ['Broken Strings']);
If you don’t want to use an array when passing a single parameter, the handlerWithParams will need to be capable of determining if an array has been passed or not.
function paramsToHandler(handler, params) {
if (params.constructor.toString().indexOf('Array') === -1) {
params = [params];
}
return handler.apply(this, params);
}
var mariachi = form.elements.mariachi;
mariachi.onclick = paramsToHandler(mariachiHandler, 'Broken Strings');