Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

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.

Live example here

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.

share|improve this question

2 Answers 2

up vote 2 down vote accepted

You should probably have a look at http://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.

share|improve this answer
    
Thanks @Arne! That's very helpful. –  DeeDee Jan 8 '13 at 14:48
    
As soon as I'm able to vote up your answer, I will. –  DeeDee Jan 8 '13 at 17:28
    
@DeeDee I think you can accept it if you think it answered your question (tick box under the score). –  Quentin Pradet Feb 18 '13 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."

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.