tomantford
tomantford

Reputation: 182

JavaScript adding and removing <tr> with EventListener and jQuery

Apologies for the very messy code. I'm confused by where my $().ready(function() and individual functions should be placed.

What works: 1) $(".calc").change(function() - this updates a span and divs with data selected from a table populated from a database 2) When the page is loaded, before the $(".calc").change(function() is called the function addRow(e) manages to write "hey" to the console log, but fails with ReferenceError: Can't find variable: tbody addRow (furniture-product.php, line 396). Once the $(".calc").change(function() is run, the console log no longer works

What does not work: 1) function addRow(e) 2) function removeRow(e)

I'm certain it's a case of having something small in the wrong place, but I have tried moving parts of the script around but with no success.

$().ready(function () {

    "use strict";
    var tbody = document.getElementById("the-tbody");

    document.getElementById("btn-add").addEventListener("click", addRow, false);

    tbody.addEventListener("click", removeRow, false);


    var radios = $('input[type=radio]');
    radios.on('change', function () {
        radios.each(function () {
            var radio = $(this);
            radio.closest('.article-option')[radio.is(':checked') ? 'addClass' : 'removeClass']('highlight');
        });
    });


    $(".calc").change(function () {
        calctotal()

    });

});



function addRow(e) {
    console.log("hey");
    var product_id = $('input[name="product_name"]').val();
    var product_price = $('input[name="product_price"]').val();
    var row = document.createElement('tr');
    row.innerHTML = '<td><input type="hidden" name="item_id[]" value="' + product_id + '"><p>' + name + '</p><input type="hidden" name="price[]" value="' + product_price + '" class="price">&pound;<span id="amount" class="amount">0</span> <span class="remove">[x]</span></td>';
    tbody.appendChild(row);
    update_amounts();
}



function removeRow(e) {
    var elm;
    for (elm = e.target; elm !== this; elm = elm.parentNode) {
        if (/\bremove\b/.test(elm.className)) {
            removeElement(elm.parentNode);
            e.stopPropagation();
            return;
            update_amounts();
        }
    }
}

function calctotal() {
    var total = 0;

    var radios = $('input[type=radio]');

    radios.each(function () {
        var radio = $(this);
        radio.closest('.article-option')[radio.is(':checked') ? 'addClass' : 'removeClass']('highlight');

    });



    $(".calc:checked").each(function () {
        var a = this.value.split(",");
        total += parseFloat(a[0]);
        name = (a[1]);
        image = (a[2]);
        curtainid = (a[3]);
        curtaindesc = (a[4]);


        $("span.img").html('<div class="row curtain-img"><img src="images/furniture/' + image + '" class="img-responsive img-rounded" style="border: 5px solid #5f4865"></div>');


        $("div#product_name").html('<input type="hidden" name="product_name" value="' + curtainid + '">' + name + '');
        $("div#product_desc").html('' + curtaindesc + '');
        $("div#product_add").html('<input type="button" id="btn-add" value="Add">');
        $("div#product_price").html('<input type="hidden" name="product_price" value="' + total.toFixed(2) + '"><strong>&pound;' + total.toFixed(2) + '</strong>');

    });


}

Quite simply the HTML is

<table id="myTable">

<tbody id="the-tbody"></tbody>

</table>

<input type="button" id="btn-add" value="Add">

JS Fiddle: http://jsfiddle.net/pw25p3qt/

Upvotes: 0

Views: 140

Answers (2)

Roamer-1888
Roamer-1888

Reputation: 19288

There's a number of issues with the code - too many to list.

Here's a working version, with some of the original code stripped out, leaving just the raw add/remove functionality.

HTML

<table id="myTable" border>
    <thead>
        <tr><th>Product</th><th>Unit Price</th><th>Quantity</th><th>Total Price</th><th>Remove</th></tr>
    </thead>
    <tbody id="the-tbody"></tbody>
    <tr><td id="totalCell" colspan="5">Total: &pound;<span id="total"></span></td></tr>
</table>
<input type="button" id="btn-add" value="Add" />

Javascript

$(function() {
    "use strict";
    $("#btn-add").on('click', addRow);
    var tbody = $("#the-tbody").on('click', '.remove', removeRow);//delegate click handling to the tbody element.
    calc();

    function calc() {
        var sum = 0;
        $('tr.product').each(function() {
            var qty = Number($(this).find('.qty').text()),
                price = Number($(this).find('.price').text()),
                amount = (qty * price).toFixed(2);
            $(this).find('.amount').text(amount);
            sum += Number(amount);
        });
        $('#total').text(sum.toFixed(2));
    }
    function addRow(e) {
        $('<tr class="product"><td>Sample Product</td><td>&pound;<span class="price">1.00</span></td><td><span class="qty">1</span></td><td>&pound;<span class="amount"></span></td><td><span class="remove">[x]</span></td></tr>').appendTo(tbody);
        calc();
    }
    function removeRow(e) {
        $(this).closest("tr").remove();
        calc();
    }
});

DEMO

Note how the Remove buttons' click action is delegated to the tbody element. This is necessary to ensure that every remove button that is added later (as part of a product row) has the required action without the need to attach the click handler individually.

Note also that all the worker functions, addRow(), removeRow() and calc() are now defined inside the $(function() {}) structure. This ensures that vars such as tbody remain in scope (without resorting to the global scope).

Upvotes: 1

Naveen Chandra Tiwari
Naveen Chandra Tiwari

Reputation: 5123

Ahhh.. You all doing correct. Just define your variable just on top, ie. before document.ready().

  var tbody=null;
  $().ready(function () {

"use strict";
tbody = document.getElementById("the-tbody");
 document.getElementById("btn-add").addEventListener("click", addRow, false);

tbody.addEventListener("click", removeRow, false);


var radios = $('input[type=radio]');
radios.on('change', function () {
    radios.each(function () {
        var radio = $(this);
        radio.closest('.article-option')[radio.is(':checked') ? 'addClass' : 'removeClass']('highlight');
    });
   });


  $(".calc").change(function () {
    calctotal()

  });

  });

Upvotes: 1

Related Questions