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:
But what I really want to do is:
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"> </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"> </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
}