Home > Software engineering >  Dynamically add rows to an invoice-form with JQuery
Dynamically add rows to an invoice-form with JQuery

Time:02-19

I have a formfield with a static row for an invoice position. With and - buttons I can add or remove additional rows for invoice positions dynamically. This works fine, but within each row I have a have a selectbox that switches the calculation method for the row (from km- to hour- or misc-based). This last feature only works for the first static row, not for the added rows?

HTML

    <form action="" method="post">
        <div >
            <div id="position_0" >
                <div >
                    <label for="description" >Beschreibung</label>
                    <textarea  id="description_0" name="description_0" rows="1"></textarea>
                </div>
                <div >
                    <label for="date" >Tag der Leistung</label>
                    <input type="text"  id="date_0" name="date_0">
                </div>
                <div >
                    <label for="amount" >Menge</label>
                    <input type="text"  id="amount_0" name="amount_0">
                </div>
                <div >
                    <label for="type" >Abrechnungsform</label>
                    <select  id="type_0" name="type_0">
                        <option value="km" selected>Kilometer</option>
                        <option value="hours">Stunden</option>
                        <option value="misc">Sonstiges</option>
                    </select>
                </div>
                <div >
                    <label for="price" >Einzelpreis</label>
                    <input type="text"  id="price_0" name="price_0" value="{{price_km}}">
                </div>
                <div >
                    <label for="sum" >Summe</label>
                    <input type="text"  id="sum_0" name="sum_0">
                </div>
            </div>
        </div>
        <div id="multiple"></div>
        <button type="submit" >Speichern</button>
    </form>
    <button  onclick="addItems()"><i ></i></button>
    <button  onclick="removeItems()"><i ></i></button>

Javascript/JQuery

<script>
    var formatter = new Intl.NumberFormat('de-DE', {
        style: 'currency',
        currency: 'EUR',
    });

    var km = 0.97;
    var hours = 12;
    var misc = 0;

    // THIS DOES NOT WORK START
    $("#multiple").each(function () {
        var n = $(this).find("div.mb-3").length;
        $('#type_'   n).on('change', function () {
            if (this.value === 'km') {
                $('#price_'   n).val(formatter.format(km));
            } else if (this.value === 'hours') {
                $('#price_'   n).val(formatter.format(hours));
            } else if (this.value === 'misc') {
                $('#price_'   n).val(formatter.format(misc));
            }
        });
    });
    // THIS DOES NOT WORK END

    function addItems() {
        $("#multiple").each(function () {
            var i = $(this).find("div.col").length;
            var n = (i / 6)   1;
            $(this).append(`<div >
            <div id="position_`   n   `" >
                <div >
                    <textarea  id="description_`   n   `" name="description_`   n   `" rows="1"></textarea>
                </div>
                <div >
                    <input type="text"  id="date_`   n   `" name="date_`   n   `">
                </div>
                <div >
                    <input type="text"  id="amount_`   n   `" name="amount_`   n   `">
                </div>
                <div >
                    <select  id="type_`   n   `" name="type_`   n   `">
                        <option value="km" selected>Kilometer</option>
                        <option value="hours">Stunden</option>
                        <option value="misc">Sonstiges</option>
                    </select>
                </div>
                <div >
                    <input type="text"  id="price_`   n   `" name="price_`   n   `" value="{{price_km}}">
                </div>
                <div >
                    <input type="text"  id="sum_`   n   `" name="sum_`   n   `">
                </div>
            </div>
        </div>`);
        });
    }

    function removeItems() {
        $("#multiple").each(function () {
            var n = $(this).find("div.mb-3").length;
            if (n != 0) {
                $("#position_"   n).parents("div.mb-3").remove();
            }
        });
    }
</script>

CodePudding user response:

Only the initial items are "wired" the change event because you run

// this line loops only on the initial items
$("#multiple").each(function () {

To solve this you have to set an .on(event) function

// this is NOT a complete example
// 1. add a generic class to all the selects
<select  id="type_0" name="type_0">
                    <option value="km" selected>Kilometer</option>
                    <option value="hours">Stunden</option>
                    <option value="misc">Sonstiges</option>
                </select>

// 2. Set the on event, but all thing relative to the element (not fixed to the index or id
$('.mytypeselect').on('change', function () {
     var self = $(this);
     var row = self.closest(".row"); // find the row the select belongs at
     if (self.val() === 'km') {
         // find the input inside the row to change
         row.find('.mypriceinput').val(formatter.format(km)); 

CodePudding user response:

This is not optimal, but it solves my problem

// First row of the invoice
$('select#type_0').on('change', function () {
        if ($(this).val() === 'km') {
            $(this).parents('div').find('#price_0').val(formatter.format(km));
        } else if ($(this).val() === 'hours') {
            $(this).parents('div').find('#price_0').val(formatter.format(hours));
        } else if ($(this).val() === 'misc') {
            $(this).parents('div').find('#price_0').val(formatter.format(misc));
        }
    });

// Everytime the DOM changes
    $("#multiple").bind("DOMSubtreeModified", function () {
        $('.mytypeselect').on('change', function () {
            var sibling = $(this).parents('div');
            var n = (($(this).attr('id')).split('_'))[1];
            if ($(this).val() === 'km') {
                sibling.find('#price_'   n).val(formatter.format(km));
            } else if ($(this).val() === 'hours') {
                sibling.find('#price_'   n).val(formatter.format(hours));
            } else if ($(this).val() === 'misc') {
                sibling.find('#price_'   n).val(formatter.format(misc));
            }
        });
    });
  • Related