I am a JavaScript beginner. Here's a fictional example which isolates the functionality mentioned in the subject line. I hope to employ this functionality as part of a larger web application in the real world soon.
An HTML5 page containing a simple form with one row:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Add Elements to a Form</title>
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link rel="stylesheet" href="css/styles.css">
</head>
<body>
<div id="addrow">
<label for="addnum">Add Rows:
<input type="text" name="addnum" id="addnum" value="" size="2">
</label>
<input type="button" name="addbtn" id="addbtn" value="Go!">
</div>
<br>
<fieldset id="lunches">
<legend>Let's do Lunch</legend>
<div class="formrow">
<span>My </span>
<select name="lunch[]" class="dropdown">
<option value="">Select a lunch item</option>
<option value="baloney">Baloney</option>
<option value="yogurt">Yogurt</option>
<option value="apple">Apple</option>
<option value="cheese">Government Cheese</option>
</select>
<span> has a </span>
<select name="firstorlast[]" class="dropdown">
<option value="first">First</option>
<option value="second">Second</option>
</select>
<span> name. It's</span>
<input type="text" name="name[]" value="Specify a Name" size="20">
</div>
</fieldset>
<script src="js/utilities.js"></script>
<script src="js/addelements.js"></script>
</body>
</html>
addelements.js
which contains the functionality for adding and removing rows of input. Each added row will have a button which, when clicked, will delete the row from the form. The first row cannot and should not be deleted:
window.onload = function() {
'use strict';
//U.addEvent is a cross-browser way to add an event handler to a DOM object.
//U.$ is a shortcut to getElementById
//Idea taken from Larry Ullman's "Modern Javascript: Develop and Design
U.addEvent(U.$('addbtn'), 'click', addRows);
}
function addRows() {
'use strict';
var numRowsToAdd = U.$('addnum').value;
for(var i = 0; i < numRowsToAdd; i++){
addRow();
}
}
function addRow() {
'use strict';
var sourceNode = document.querySelector('.formrow');
var newRow = sourceNode.cloneNode(true);
//every row except the first row should have a delete button associated with it.
var delButton = document.createElement('input');
delButton.className = 'delbtn';
delButton.type = 'button';
delButton.name = 'delbtn';
delButton.value = 'Delete This Row';
U.addEvent(delButton, 'click', function() {removeRow(delButton)});
newRow.appendChild(delButton);
var fieldset = U.$('lunches');
fieldset.appendChild(newRow);
}
function removeRow(obj) {
'use strict';
var theRow = obj.parentNode;
var theRowParent = theRow.parentNode;
theRowParent.removeChild(theRow);
}
relevant code from utilities.js
:
var U = {
// For getting the document element by ID:
$: function(id) {
'use strict';
if (typeof id == 'string') {
return document.getElementById(id);
}
},
addEvent: function(obj, type, fn) {
'use strict';
if (obj && obj.addEventListener) { // W3C
obj.addEventListener(type, fn, false);
} else if (obj && obj.attachEvent) { // Older IE
obj.attachEvent('on' + type, fn);
}
}
}
If you copy and save these into the proper files with the proper path structure, it should work for you.
2 Answers 2
You should probably have a look at https://stackoverflow.com/questions/5805059/select-placeholder#answer-8442831 and make the first line non-selectable by HTML only.
It's done by making the first element selected, disabled and by adding a display:none.
-
\$\begingroup\$ As soon as I'm able to vote up your answer, I will. \$\endgroup\$DeeDee– DeeDee2013年01月08日 17:28:09 +00:00Commented Jan 8, 2013 at 17:28
-
\$\begingroup\$ @DeeDee I think you can accept it if you think it answered your question (tick box under the score). \$\endgroup\$Quentin Pradet– Quentin Pradet2013年02月18日 19:59:34 +00:00Commented Feb 18, 2013 at 19:59
I would suggest using event delegation instead of adding event handlers to each 'Delete' button individually.
This can be done by attaching a click event listener to a parent element, then filtering the event target for a specified className
.
For example, if we added a function U.on()
as follows (and utilizing U.addEvent()
that you already have):
!(function () {
'use strict';
/**
* helper function to delegate/attach DOM events
* @param {String} root selector for event root element
* @param {String} event single event name
* @param {String} child className of target element
* @param {Function} fn event handler
*/
function on(root, eventName, child, fn) {
var to = document.querySelector(root);
var handler = delegator(child, fn);
U.addEvent(to, eventName, handler);
}
/**
* fires event handler if event target matches className
* @param {String} className class to match
* @param {Function} fn event handler to call
*/
function delegator(className, fn) {
return function (e) {
if (e.target.classList.contains(className)) {
fn.call(this, e);
}
};
}
U.on = on;
})();
We could delegate all of the 'Delete' button click events to the parent form element, by doing to following:
on('#lunches', 'click', 'delbtn', function (e) {
removeRow(e.target);
});
This basically says, "If a click happens inside an element with the id lunches
, and the click happened on an element with the class .delbtn
, then call this function that I'm passing in as the last argument."
Explore related questions
See similar questions with these tags.