smoseley
July 30 '03, 06:35 PM
Here's a little script I made (attached at the bottom) that creates a dynamically expanding input. Overloading the <tab> key normally used to move to the next field in a form, I now generate a new field when <tab> is pressed. I also overload the <up> and <down> arrow keys so that if you click on one of the fields and press <up>, for instance, it will swap that field with the previous field. There's some decent exception handling in this, too. For instance, it won't let you move the first item up, and it won't create a new field if the last one is blank. And if you clear an existing field, it will erase the whole text box.
Anyhow, here's how the whole thing works:
The load() function basically sets up our page with some events. It loops through all of the elements in the form and sets their onblur and onkeyup events, overloading them with the appropriate functions when those events are registered.
function load() {
var x = document.forms[0].elements;
for (var i=0;i<x.length;i++) {
x[i].onblur = function (e) {lostFocus(e)};
x[i].onkeyup = function (e) {keyPressed(e)};
}
}
The lostFocus() function is called when an input box is clicked off of (or tabbed out of). It first determines that the element that lost focus was a text box. Then, it checks to see if it is the last item in the list (using document.getElementsByTagName to retrieve all of the inputs on the page into an array). If it is the last input and has been filled, it adds a new input after it by calling the newInput() function. Otherwise, if the input is empty, it removes it from the page.
function lostFocus(e) {
if (!e) {
e = window.event;
var target = e.srcElement;
} else {
var target = e.target;
}
if (target.type == 'text') {
var id = 0;
var inputs = document.getElementsByTagName('input');
if (inputs[inputs.length - 1] == target) {
if (target.value.length > 0) {
newInput(target.name, target.id);
}
} else {
if (target.value.length == 0) {
document.getElementById('inputList').removeChild(target.parentElement)
}
}
}
return true;
}
The keyPressed() function overloads the <up> and <down> arrow keys by calling the move() function with a vector value telling it how many places to move the current input's parent div (each input is encapsulated in its own div for DHTML friendliness).
function keyPressed(e) {
if (!e) {
e = window.event;
var target = e.srcElement;
var key = e.keyCode;
} else {
var target = e.target;
var key = e.which;
}
var div = target.parentElement;
if (key == 38) {
move(div, -1);
} else if (key == 40) {
move(div, 1);
}
return true;
}
The move() function takes the input div's parent (the outermost div) and checks to make sure there is another child at the specified movement location. If that check passes, the function swaps the two elements using a one-two-one replacement procedure.
function move(element, distance) {
var parent = element.parentElement;
var index = 0;
for (var i = 0; i < parent.children.length; i++) {
if (parent.children[i] == element) {
index = i;
}
}
if (element.value != '') {
if (index == parent.children.length - 1) {
if (distance > 0) {
return true;
} else {
newInput(element.name, element.id);
}
}
if (parent.children[index + distance].value != '' && index + distance > 0) {
parent.removeChild(element);
parent.insertBefore(element, parent.children[index + distance]);
parent.children[index + distance].focus();
}
}
}
The newInput() function creates a new DIV element and a new INPUT element inside it using DOM. It then appends them to the end of the input list.
function newInput(name, prevId) {
var id = 1 + prevId;
var newDiv = document.createElement('div');
var newInput = document.createElement('input');
newInput.name = name;
newInput.id = id;
newDiv.appendChild(newInput);
document.getElementById('inputList').appendChild(newDiv);
newInput.focus();
load();
}
And here's the body of the page... it's relatively simple, consisting of a form with a submit button and a div as its children. The div id of "inputList" is applicable to the current script. The body's onload event creates a new input
<body onload="newInput('test', 0); load();">
<form name="whatever" ID="Form1">
<input type="submit" value="Save" NAME="submit" ID="Submit1">
<div id="inputList">
</div>
</form>
</body>
And here's the file (note.. the file has been modified for the explanation above, and differs slightly in content):
:)
Anyhow, here's how the whole thing works:
The load() function basically sets up our page with some events. It loops through all of the elements in the form and sets their onblur and onkeyup events, overloading them with the appropriate functions when those events are registered.
function load() {
var x = document.forms[0].elements;
for (var i=0;i<x.length;i++) {
x[i].onblur = function (e) {lostFocus(e)};
x[i].onkeyup = function (e) {keyPressed(e)};
}
}
The lostFocus() function is called when an input box is clicked off of (or tabbed out of). It first determines that the element that lost focus was a text box. Then, it checks to see if it is the last item in the list (using document.getElementsByTagName to retrieve all of the inputs on the page into an array). If it is the last input and has been filled, it adds a new input after it by calling the newInput() function. Otherwise, if the input is empty, it removes it from the page.
function lostFocus(e) {
if (!e) {
e = window.event;
var target = e.srcElement;
} else {
var target = e.target;
}
if (target.type == 'text') {
var id = 0;
var inputs = document.getElementsByTagName('input');
if (inputs[inputs.length - 1] == target) {
if (target.value.length > 0) {
newInput(target.name, target.id);
}
} else {
if (target.value.length == 0) {
document.getElementById('inputList').removeChild(target.parentElement)
}
}
}
return true;
}
The keyPressed() function overloads the <up> and <down> arrow keys by calling the move() function with a vector value telling it how many places to move the current input's parent div (each input is encapsulated in its own div for DHTML friendliness).
function keyPressed(e) {
if (!e) {
e = window.event;
var target = e.srcElement;
var key = e.keyCode;
} else {
var target = e.target;
var key = e.which;
}
var div = target.parentElement;
if (key == 38) {
move(div, -1);
} else if (key == 40) {
move(div, 1);
}
return true;
}
The move() function takes the input div's parent (the outermost div) and checks to make sure there is another child at the specified movement location. If that check passes, the function swaps the two elements using a one-two-one replacement procedure.
function move(element, distance) {
var parent = element.parentElement;
var index = 0;
for (var i = 0; i < parent.children.length; i++) {
if (parent.children[i] == element) {
index = i;
}
}
if (element.value != '') {
if (index == parent.children.length - 1) {
if (distance > 0) {
return true;
} else {
newInput(element.name, element.id);
}
}
if (parent.children[index + distance].value != '' && index + distance > 0) {
parent.removeChild(element);
parent.insertBefore(element, parent.children[index + distance]);
parent.children[index + distance].focus();
}
}
}
The newInput() function creates a new DIV element and a new INPUT element inside it using DOM. It then appends them to the end of the input list.
function newInput(name, prevId) {
var id = 1 + prevId;
var newDiv = document.createElement('div');
var newInput = document.createElement('input');
newInput.name = name;
newInput.id = id;
newDiv.appendChild(newInput);
document.getElementById('inputList').appendChild(newDiv);
newInput.focus();
load();
}
And here's the body of the page... it's relatively simple, consisting of a form with a submit button and a div as its children. The div id of "inputList" is applicable to the current script. The body's onload event creates a new input
<body onload="newInput('test', 0); load();">
<form name="whatever" ID="Form1">
<input type="submit" value="Save" NAME="submit" ID="Submit1">
<div id="inputList">
</div>
</form>
</body>
And here's the file (note.. the file has been modified for the explanation above, and differs slightly in content):
:)