简体   繁体   中英

How to access existing tr and fill its td using json from ajax success without generating new row

I am using CouchCMS . In CouchCMS there is a concept of repeatable regions. This in fact generates tables and displays the repeatable contents in it.

I have the repeatable region defined as:

<cms:repeatable name="item_detail" label="Item Detail" order="10" >
    
    <cms:editable name="product" label="Product" type="dropdown" opt_values="Select =- | <cms:pages masterpage='product/product.php' order='asc' orderby='product_name'><cms:show product_name /><cms:if '<cms:not k_paginated_bottom />'>|</cms:if></cms:pages>" order="1" />
    <cms:editable name="product_hsn" label="HSN" type="text" order="2" />hsn,qty,price,gst,amount
    <cms:editable name="product_qty" label="Quantity" type="text" order="3" />
    <cms:editable name="product_price" label="Price" type="text" order="4" />
    <cms:editable name="product_tax" label="Tax" type="text" order="5" />
    <cms:editable name="product_line_total_amount" label="Amount" type="text" order="6" />

</cms:repeatable>  

Where the editables are the regions where we can fill in the data by bounding them to the respective textboxes/ selects, etc.

Now What I am trying to do is:

  1. Select a value from the dropdown of the editable named "product".
  2. When an option is selected, an AJAX is called. This AJAX in turn returns some data.
  3. I am able to get the data, console log it or display it in a div or a table.

But what I really want to do is:

  1. Since the repeatable region is shown is the form of a table, the exists. I want to be able to just get the AJAX JSON data displayed in the of the existing data.
  2. If you see the editables above, a table exists with each editables' select/textbox in the, there are:
  • product (select, for product name)
  • product_hsn (textbox, with to be created and be filled by AJAX JSON)
  • product_qty (textbox, with to be created but needs to be blank)
  • product_price (textbox, with to be created and be filled by AJAX JSON)
  • product_tax (textbox, with to be created and be filled by AJAX JSON)
  • product_line_total_amount (textbox, with to be created but needs to be blank)

Now the repeatable region creates a structure as follows ( for the above defined repeatable region):

Product HSN Quantity Price Tax Amount Delete
<div>
    <p class="addRow" id="addRow_f_item_detail"><a>Add a Row</a></p>
</div>

I can add new rows also right out of the box when using repeatable regions. If one observes ids and the names have a zero [0] this keeps on incrementing as one would add the new rows. The script helping in this above code generation is:

if ( !window.COUCH ) var COUCH = {};
    $(function(){
        $('table.rr > tbody').sortable({
            axis: "y",
            handle: ".dg-arrange-table-rows-drag-icon",
            helper: function (e, ui) { 
                // https://paulund.co.uk/fixed-width-sortable-tables
                ui.children().each(function() {                
                    $(this).width($(this).width());
                });
            return ui;
        },
        update: function( event, ui ){
            var row = ui.item;
            var tbody = $( row ).closest( 'tbody' );
            tbody.trigger('_reorder');
        },
        start: function( event, ui ){    
            var row = ui.item;
            row.trigger('_reorder_start');
        },
        stop: function( event, ui ){
            var row = ui.item;
            row.trigger('_reorder_stop');
        },
    });
});
COUCH.rrInit = function( field_id, default_row ){
    var $field = $('#'+field_id);
    $field.tableGear({addDefaultRow:default_row, stackLayout:1});
    $field.on('click', '.col-actions .add-row', function(){
        var $this = $(this);
        var row_id = $this.attr('data_mosaic_row');
        var add_btn = $('#addRow_'+field_id+' a');
        add_btn.trigger("click", [row_id]);
    });
}
COUCH.t_confirm_delete_row = "Delete this row?";
COUCH.t_no_data_message = "- No Data -";

Just in case if required this is my AJAX code, using which I am able to add a new but it is in a New while I want the to be appended to the same that contains the existing repeatable regions. AJAX CODE:

$(document).on('change','select',function() {
    var data = "";
    $.ajax({
        type:"GET",
        url : "<cms:show k_site_link />generate/quotation-ajax.php",
        data: 
            "select_id="+$(this).val(),
        async: false
    }).done(function(data) {
        console.log(data);
        var trHTML = '';
        $.each(data.product_details, function (i, item) {
            trHTML += "<tr id='f_item_detail-" + i + "'>" + '<td class="editable k_element_product_hsn"><div style="position:relative;"><input type="bound" name=" f_item_detail[0][product_hsn]" id="f_item_detail-[0]-product_hsn" class="form-control" value="' + item.product_hsn + '"/></div></td>' +
            // '<td style="position:relative;"><input type="bound" name=" f_item_detail[0][product_price]" id="f_item_detail-[0]-product_price" class="form-control" value="' + item.product_price + '"/></td>' +
            // '<td style="position:relative;"><input type="bound" name=" f_item_detail[0][product_tax]" id="f_item_detail-[0]-product_tax" class="form-control" value="' + item.product_tax + '"/></td>' +
            '</tr>';
        });
        $('#f_item_detail').append(trHTML);
    })
});

And my AJAX file has the code:

<?php require_once('../couch/cms.php'); ?>
<cms:set selected_product="<cms:gpc 'select_id' method='get' />" scope="global" />
<cms:content_type 'application/json'/>
<cms:template title="Quotation AJAX" hidden='1' parent="_generate_" />
    {
        "product_details": 
        [
            <cms:pages masterpage='product/product.php' custom_field="product_name=<cms:show selected_product />" >
            {
                "product_hsn": "<cms:addslashes><cms:show product_hsn/></cms:addslashes>",
                "product_price": "<cms:addslashes><cms:show min_selling_cost/></cms:addslashes>",
                "product_tax": "<cms:addslashes><cms:show tax_on_purchase/></cms:addslashes>"   
            }<cms:if "<cms:not k_paginated_bottom/>">,</cms:if>
            </cms:pages>
        ]
    }
<?php COUCH::invoke(); ?>

What I am looking for: Add the AJAX success JSON values to the respective textboxes in the existing, and rather than adding a new or or. I am unable to set the correct jQuery. Any help would be really appreciated.

Thanks in advance. Regards: @Swati: Full HTML in this fiddle (with some changes in the AJAX part, which partially works and outputs what I want to achieve. The value is put into the textbox but for each new row the same textbox value is updated from the first row, if i could update the textbox values row wise it would be great)

EDIT #1 I have used your code (@Swati) as follows and yes it works fine (to an extent).

<script type="text/javascript">
    $(document).ready(function(){
        $("#f_item_detail-0-product").select2();
        $('input#f_item_detail-0-product_hsn').attr('readonly', true).addClass("form-control");
        $('input#f_item_detail-0-product_qty').attr('onchange', 'line_total()');
        $('input#f_item_detail-0-product_price').attr('onchange', 'line_total()');
        $('input#f_item_detail-0-product_tax').attr('readonly', true).addClass("form-control");
        $('input#f_item_detail-0-line_tax_amount').attr('readonly', true).addClass("form-control");
        $('input#f_item_detail-0-product_line_total_amount').attr('readonly', true).addClass("form-control");
    });
    
    var counter = 0;
    $(document).ready(function() {
        $(".addRow").click(function(){
            counter++;
            $("#f_item_detail-" + counter + "-product").select2();
        });
    });

    $(document).on('change','select',function() {
        var data = "";
        var i = 0;
        var indexs = $(this).closest("tr").index();//get index no
        console.log(indexs);

        $.ajax({
            type:"GET",
            url : "<cms:show k_site_link />generate/quotation-ajax.php",
            data: 
                "select_id="+$(this).val(),
            async: false
        }).done(function(data) {
            $('#f_item_detail-' + indexs + '-product_hsn').val(data.product_details[i].product_hsn).attr('readonly', true).addClass("form-control");

            $('#f_item_detail-' + indexs + '-product_qty').attr('onchange', 'line_total()');

            $('#f_item_detail-' + indexs + '-product_price').val(data.product_details[i].product_price).attr('onchange', 'line_total()');

            $('input#f_item_detail-' + indexs + '-product_tax').val(data.product_details[i].product_tax).attr('readonly', true).addClass("form-control");

            $('#f_item_detail-' + indexs + '-line_tax_amount').attr('readonly', true).addClass("form-control");

            $('#f_item_detail-' + indexs + '-product_line_total_amount').val(data.product_details[i].product_line_total_amount).attr('readonly', true).addClass("form-control");
        });
    });
            
    function line_total(){
        var line_qty = $('input#f_item_detail-' + indexs + '-product_qty').val();
        var line_tax = $('input#f_item_detail-' + indexs + '-product_tax').val();
        var line_cost =  $('input#f_item_detail-' + indexs + '-product_price').val();
        var line_tax_amount = parseFloat(((line_cost * line_tax)/100) * line_qty).toFixed(2);
        var result = parseFloat((+line_qty * +line_cost) + +line_tax_amount).toFixed(2);
        $('#f_item_detail-' + indexs + '-line_tax_amount').val(line_tax_amount).attr('hidden',true);
        $('#f_item_detail-' + indexs + '-product_line_total_amount').val(result);
    }

</script>

It is solving the issue of going back and editing the product and hence updating the line item value as you had suggested.

But if you see the function line_total() it breaks. And the total are not calculated. What do you suggest? How can we use the indexs value or something else. Also, I would be greatful if you could also suggest me how can we display the GST Amount total and Amount Total at the end with a Grand Total (GST Amount Total + Amount Total), I would be really greatful.

I am not good with javascript or jQuery at all.

Whenever your select-box gets change you can simply get closest tr from that select-box then .find() to find required inputs and add value there.

Demo Code :

 $(document).on('change', 'select', function() { var selector = $(this).closest("tr") //get closest tr /* $.ajax({ type: "GET", url: "<cms:show k_site_link />generate/quotation-ajax.php", data: "select_id=" + $(this).val(), async: false }).done(function(data) {*/ //find your input and add value there selector.find('.k_element_product_hsn input').val("ac"); //data.product_details[i].product_hsn selector.find('.k_element_product_price input').val(124); //data.product_details[i].product_price selector.find('.k_element_product_tax input').val(23); //data.product_details[i].product_tax selector.find('.k_element_product_line_total_amount input').val(4356); //data.product_details[i].product_line_total_amount selector.find('.k_element_product_qty input').val(2); //data.product_details[i].product_qty /*} })*/ });
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script> <table> <tbody> <tr id="newDataRow_f_item_detail" class="newRow even"> <td class="dg-arrange-table-rows-drag-icon">&nbsp;</td> <td class="editable k_element_product"> <div style="position:relative;"> <select name="data[xxx][product]" idx="data-xxx-product" id="data-xxx-product"> <option value="-">Select</option> <option value="3Ply Mask">3Ply Mask</option> <option value="Laptop i3 4th Gen">Laptop i3 4th Gen</option> </select> </div> </td> <td class="editable k_element_product_hsn"> <div style="position:relative;"><input type="text" idx="data-xxx-product_hsn" id="data-xxx-product_hsn" name="data[xxx][product_hsn]" value=""> </div> </td> <td class="editable k_element_product_qty"> <div style="position:relative;"><input type="text" idx="data-xxx-product_qty" id="data-xxx-product_qty" name="data[xxx][product_qty]" value=""> </div> </td> <td class="editable k_element_product_price"> <div style="position:relative;"><input type="text" idx="data-xxx-product_price" id="data-xxx-product_price" name="data[xxx][product_price]" value=""> </div> </td> <td class="editable k_element_product_tax"> <div style="position:relative;"><input type="text" idx="data-xxx-product_tax" id="data-xxx-product_tax" name="data[xxx][product_tax]" value=""> </div> </td> <td class="editable k_element_product_line_total_amount"> <div style="position:relative;"><input type="text" idx="data-xxx-product_line_total_amount" id="data-xxx-product_line_total_amount" name="data[xxx][product_line_total_amount]" value=""> </div> </td> <td class="delete"><input type="checkbox" name="delete[]" value="" id="deleteNULL_STRING" style="display: none;" /><label for="deleteNULL_STRING"> <img src="http://localhost/CTO/GXCPL-Billing/couch/addons/repeatable/tablegear/delete.gif" alt="Delete Row" /></label></td> </tr> <tr id="newDataRow_f_item_detail" class="newRow even"> <td class="dg-arrange-table-rows-drag-icon">&nbsp;</td> <td class="editable k_element_product"> <div style="position:relative;"> <select name="data[xxx][product]" idx="data-xxx-product" id="data-xxx-product"> <option value="-">Select</option> <option value="3Ply Mask">3Ply Mask</option> <option value="Laptop i3 4th Gen">Laptop i3 4th Gen</option> </select> </div> </td> <td class="editable k_element_product_hsn"> <div style="position:relative;"><input type="text" idx="data-xxx-product_hsn" id="data-xxx-product_hsn" name="data[xxx][product_hsn]" value=""> </div> </td> <td class="editable k_element_product_qty"> <div style="position:relative;"><input type="text" idx="data-xxx-product_qty" id="data-xxx-product_qty" name="data[xxx][product_qty]" value=""> </div> </td> <td class="editable k_element_product_price"> <div style="position:relative;"><input type="text" idx="data-xxx-product_price" id="data-xxx-product_price" name="data[xxx][product_price]" value=""> </div> </td> <td class="editable k_element_product_tax"> <div style="position:relative;"><input type="text" idx="data-xxx-product_tax" id="data-xxx-product_tax" name="data[xxx][product_tax]" value=""> </div> </td> <td class="editable k_element_product_line_total_amount"> <div style="position:relative;"><input type="text" idx="data-xxx-product_line_total_amount" id="data-xxx-product_line_total_amount" name="data[xxx][product_line_total_amount]" value=""> </div> </td> <td class="delete"><input type="checkbox" name="delete[]" value="" id="deleteNULL_STRING" style="display: none;" /><label for="deleteNULL_STRING"> <img src="http://localhost/CTO/GXCPL-Billing/couch/addons/repeatable/tablegear/delete.gif" alt="Delete Row" /></label></td> </tr> </tbody> </table>

Updated 1 :

You can get index of tr which is change then using that index we can update that input values.

Updated Jquery code:

 $(document).on('change', 'select', function() {
  var data = "";
  var i = 0;
  var indexs = $(this).closest("tr").index();//get index no
  console.log(indexs)

  $.ajax({
    type: "GET",
    url: "<cms:show k_site_link />generate/quotation-ajax.php",
    data: "select_id=" + $(this).val(),
    async: false
  }).done(function(data) {

    $('#f_item_detail-' + indexs + '-product_hsn').val(data.product_details[i].product_hsn).attr('readonly', true).addClass("form-control");

    $('#f_item_detail-' + indexs + '-product_qty').attr('onchange', 'add_number()');

    $('#f_item_detail-' + indexs + '-product_price').val(data.product_details[i].product_price).attr('onchange', 'add_number()');

    $('input#f_item_detail-' + indexs + '-product_tax').val(data.product_details[i].product_tax).attr('readonly', true).addClass("form-control");

    $('#f_item_detail-' + indexs + '-line_tax_amount').attr('readonly', true).addClass("form-control");

    $('#f_item_detail-' + indexs + '-product_line_total_amount').val(data.product_details[i].product_line_total_amount).attr('readonly', true).addClass("form-control");
  });

});

Update 2 :

You can pass this as a parameter to your line_total() then use that to get closest tr index and then do calculation according to that.

Updated Jquery code:

$(document).on('change', 'select', function() {
  var indexs = $(this).closest("tr").index();
  var selector = $(this); //save selector
  var i = 0;
   $.ajax({
    type: "GET",
    url: "<cms:show k_site_link />generate/quotation-ajax.php",
    data: "select_id=" + $(this).val(),
    async: false
  }).done(function(data) {
    console.log("de");
    $('#f_item_detail-' + indexs + '-product_hsn').val(data.product_details[i].product_hsn).attr('readonly', true).addClass("form-control");

    $('#f_item_detail-' + indexs + '-product_qty').attr('onchange', 'line_total(this)'); //pass this here ...

    $('#f_item_detail-' + indexs + '-product_price').val(data.product_details[i].product_price).attr('onchange', 'line_total(this)'); //pass this here

    $('input#f_item_detail-' + indexs + '-product_tax').val(data.product_details[i].product_tax).attr('readonly', true).addClass("form-control");

    $('#f_item_detail-' + indexs + '-line_tax_amount').attr('readonly', true).addClass("form-control");

    $('#f_item_detail-' + indexs + '-product_line_total_amount').val(data.product_details[i].product_line_total_amount).attr('readonly', true).addClass("form-control");
    line_total(selector); //call this
  });

});



function line_total(selector) {
  //do same here
  var indexs = $(selector).closest("tr").index()
  var line_qty = $('input#f_item_detail-' + indexs + '-product_qty').val() != "" ? $('input#f_item_detail-' + indexs + '-product_qty').val() : 1;
  var line_tax = $('input#f_item_detail-' + indexs + '-product_tax').val();
  var line_cost = $('input#f_item_detail-' + indexs + '-product_price').val();
  var line_tax_amount = parseFloat(((line_cost * line_tax) / 100) * line_qty).toFixed(2);
  var result = parseFloat((+line_qty * +line_cost) + +line_tax_amount).toFixed(2);
  $('#f_item_detail-' + indexs + '-line_tax_amount').val(line_tax_amount).attr('hidden', true);
  $('#f_item_detail-' + indexs + '-product_line_total_amount').val(result);
  grand_total(); //call this
}

function grand_total() {
  var grand = 0;
  $(".k_element_product_line_total_amount input").each(function() {
    grand += $(this).val() != "" ? parseFloat($(this).val()) : 0
  })
  $("#grand_total").text(grand + 100); //100 is gst change it...according to your need and change id where you need to display grand total
}

So I have been trying to get things on track. Finally, I have been able to do it: The jQuery AJAX code that I was looking for to solve my problem is as below:

var counter = 0;
$(document).ready(function() {
    $(".addRow").click(function(){
        counter++;
    });
});
            
$(document).on('change','select',function() {
    var data = "";
    var i = 0;
    $.ajax({
        type:"GET",
        url : "<cms:show k_site_link />generate/quotation-ajax.php",
        data: 
            "select_id="+$(this).val(),
        async: false
    }).done(function(data) {
        $('#f_item_detail-'+ counter +'-product_hsn').val(data.product_details[i].product_hsn);
        $('#f_item_detail-'+ counter +'-product_qty').val(data.product_details[i].product_qty);
        $('#f_item_detail-'+ counter +'-product_price').val(data.product_details[i].product_price);
        $('#f_item_detail-'+ counter +'-product_tax').val(data.product_details[i].product_tax);
        $('#f_item_detail-'+ counter +'-product_line_total_amount').val(data.product_details[i].product_line_total_amount);
    })
});

I am actually creating a global counter using:

var counter = 0;
$(document).ready(function() {
    $(".addRow").click(function(){
        var globalcounter = parseFloat(counter);
        counter++;
    });
});

And then passing the value of the global counter as "counter" to the ajax(). Everytime the "Add Row" is clicked, the counter value in passed then incremented. This helps me in giving the numbers to the id's of each rows input as:

$('#f_item_detail-'+ counter +'-product_hsn').val(data.product_details[i].product_hsn);

Here i in "data.product_details[i]" remains zero because the AJAX returns details for only one product per line-item.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM