Botond Balázs Botond Balázs - 3 months ago 10
HTML Question

How to implement "add new item" functionality in JavaScript?

The title isn't very descriptive but I couldn't find a better one. Feel free to edit it.

Basically what I'm looking for is the best way to do the following:

add new item

When the user clicks "Add New Item", a new row is added with an indentical text box and drop down as above. The options I can think of are the following:


  • Hardcode the HTML in the JavaScript code. This is obviously a hideously ugly solution.

  • Assemble the HTML from DOM nodes (or jQuery objects). This is very ugly too.

  • Use a client-side template system. I used one of those once and it was pretty weird (it used
    <script language="html">
    tags to define the templates).

  • Make an ad-hoc client-side "template" and hide it somehow with CSS.

  • Make an AJAX request to fetch the HTML. This is slow and uses server resources unnecessarily.



What do you suggest? I'm not completely satisfied with any of the above solutions.

Answer

Assuming the super-simple approach and that your format is in a table:

<table>
    <tr>
        <td><input type="text" name="item_name" placeholder="item name" /></td>
        <td><select name="item_type"><option value="" selected="selected">Type</option></select></td>
    </tr>
    <tr>
        <td><input type="text" name="item_name" placeholder="item name" /></td>
        <td><select name="item_type"><option value="" selected="selected">Type</option></select></td>
    </tr>
    <tr>
        <td colspan="2" id="add">+ Add new item</td>
    </tr>
</table>

You can use the following:

$('#add').on('click',function(e){
    var $this = $(this);
    var $newRow = $this.closest('table').find('tr:first').clone();
    $newRow.find(':input').val('');
    $newRow.insertBefore($this.parent());
});

Broken down:

  1. We give the last item an ID to make it easier to bind a click event to.
  2. Use jQuery and bind the click event to that ID which:
    • Grabs the current table we're clicking within ($this.closest('table'))
    • Locates the first row within that table and duplicates it (.clone())
    • Remove any populated values that may be present (.find(':input').val(''))
    • Append this new cloned row to the table just above the "add new item" row ($newRow.insertBefore(...))

You can also take the template approach, but that's really up to you and how much control you'd like over the output.