Total Calculation From Subtotals On Repeated Group

startpoint

Active Member
Hi,
I have a repeated group with elements 'price', 'quantity' and 'subtotal'.
'Price' and 'quantity' are field elements and 'subtotal' is a calc element.

I have a calc element 'total' in another group with this code:

PHP:
$fields = array('table_name___subtotal');
$total = 0;
foreach ($fields as $field)
{
  $value = JArrayHelper::getValue($data, $field . '_raw', array());
  $thisSum = array_sum($value);
  $total += $thisSum;
}
 
return $total;

with settings:
calc on save: No;
Ajax calculation: Yes
calc onload: Yes;
Ajax observe fields: '{price},{quantity}'
Whit this settings after form is loaded total changed to 0.
If Ajax calculation set to No total is right, but without Ajax calculation.

What to change to fixed total updated at the time I change any of the values of price and quantity?
 
I ran into a similar issue a while back. I gave up on trying to get Ajax working as expected (and I'm addicted to jQuery).

This will work without having to use a calc element or Ajax...
Change the calc element to a standard field element (decimal 8,2) set to readonly - and in all 3 related elements remove any validations or javascript that might trigger an Ajax call and interfere with this javascript/jquery code - then use this code in a custom javascript file for the form.
Code:
jQuery("input[id^=repeat_table___quantity_]").change(function() {
    var qty = 0;
    var price = 0;
    var ttl = 0;
    jQuery("input[id^=repeat_table___quantity_]").each(function() {
        qty = parseFloat(jQuery(this).val());
        price = parseFloat(jQuery(this).closest(".fabrikSubGroupElements").find("input[id^=repeat_table___price_]").val());
        ttl = parseFloat(ttl + (qty * price));
    });
    ttl = ttl.toFixed(2);
    jQuery("input#parent_table___total").val(ttl);
});
 
jQuery("input[id^=repeat_table___price_]").change(function() {
    var qty = 0;
    var price = 0;
    var ttl = 0;
    jQuery("input[id^=repeat_table___price_]").each(function() {
        price = parseFloat(jQuery(this).val());
        qty = parseFloat(jQuery(this).closest(".fabrikSubGroupElements").find("input[id^=repeat_table___quantity_]").val());
        ttl = parseFloat(ttl + (qty * price));
    });
    ttl = ttl.toFixed(2);
    jQuery("input#parent_table___total").val(ttl);
});
NOTE: This won't work on existing rows (until you change a quantity or price). You'd have to duplicate that code for a 'load' event function in addition to 'change'. But so long as you are going to use this on something still in development there is no need to do that.
 
This is my new working code:
JavaScript:
window.addEvent('fabrik.loaded', function () {
  Fabrik.addEvent('fabrik.form.group.delete', function(form, ev, group) {
  if (group.id == 'group108') {
  keyupfunction();
  }
  });
});
jQuery(document).ready(function() {
    keyupfunction();
    jQuery(".repeatGroupTable").keyup(function(event)
        keyupfunction()
    );
});
function keyupfunction(){
        var total = 0;
          jQuery(".repeatGroupTable .fabrikSubGroupElements").each(function() {
             var qty = parseFloat(jQuery(this).find("input[id^=table_repeat_group___qty_]").val());
             var price = parseFloat(jQuery(this).find("input[id^=table_repeat_group___unit_price_]").val());
             var subtotal = qty * price;
             jQuery(this).find("input[id^=table_repeat_group___subtotal_]").val(subtotal);
             if(!isNaN(subtotal))
                 total+=subtotal;
                 totalfix = total.toFixed(2);   
         });
        jQuery("#main_table___total").val(totalfix);
}
But there is a problem deleting a row from "table_repeat_group". The field "main_table___total" not updated from the first time, and then delete the second row updated by decreased the value of the first deleted.
I try this code too.
JavaScript:
function doTotal() {
  var myTotal = 0;
  var myForm = Fabrik.getBlock('form_36');
  document.getElements('input[id^="table_repeat_group___subtotal_"]').each(function (el) {
    myTotal+=myForm.formElements.get(el.id).getValue();
  })
    console.log(myTotal);
  myForm.formElements.get('main_table___total').update(myTotal);
Again the same problem.
Here it does not work myTotal+=myForm.formElements.get(el.id).getValue().
The result is: number1number2number3......
Is it a bug?
 
Remember that JavaScript is relatively strongly typed. So when you "add" strings together, you get concatenated strings. And getValue() is going to return a string, even if it's a string representation of a number. So JS is concatenating "2" + "2" as "22", rather than summing 2 + 2 as 4.

If you want it to do math on string representations of numbers, you'll need to cast that getValue() to an int, like getValue().toInt(). Well, assuming it's an integer, otherwise toFloat().

-- hugh
 
Please give me a example how to modify my first code with function keyupfunction() to working properly?
I tried, but update on total field worked properly after second row deletion.
 
I really can't give you an example as I don't understand your code, I have no idea why you are using a keyup event.

Does the AJAX calc on the subtotals work?

If so, then all you should really need to do is hang a 'change' event on the subtotal calc, which calls the total calculation. We fire a 'change' on calcs when we update them from AJAX.

Plus of course on a group delete, as you already do.

-- hugh
 
Hi, cheesegrits
I changed my element subtotal to calc and subtotal work well while I change price and quantity values.
I use this code in my form_36.js file to calculate total again:
JavaScript:
function doTotal() {
  var myTotal = 0;
  var myForm = Fabrik.getBlock('form_36');
  document.getElements('input[id^="table_repeat_group___subtotal_"]').each(function (el) {
  myTotal+=parseFloat(myForm.formElements.get(el.id).getValue());
  myTotalFix = myTotal.toFixed(2);
  })
   console.log(myTotalFix);
  myForm.formElements.get('main_table___total').update(myTotalFix);

I fired this function in subtotal element with javascript change event and in total element with load event.
Now myTotal always is 0.
'table_repeat_group___subtotal_' is a calc element.
'main_table___total' is a field element.
Please help how to calculate Total.
 
Last edited:
OK, the problem is that subtotal2 isn't an input. Calc elements don't render as form input fields, they are just a span with content. So your document.getElement() won't work.

Try ...

Code:
myForm.formElements.each(function(el) {
   if (el.origId == 'oerp_sales_items_list___subtotal2') {
      myTotal += parseFloat(el.getValue());
   }
})

Although you should probably also put some defensive coding in there to make sure it has a value before running it through parseFloat(), so you don't get a NaN.

-- hugh
 
This code work only with first row in repeat group when I add a new form record and when I edit existing records.
 
I fired this function in subtotal element, price element and quantity element with javascript change event and in total element with load event.
 
Hmmm, looks like a little bug in Fabrik.

Can you test this for me:

Edit ./media/com_fabrik/js/form.js, around line 1703 is this line:

Code:
                newEl.origId = origelid;

... comment it out, like this ...

Code:
                //newEl.origId = origelid;

.. then go to Fabrik global options (button top right of any backend Fabrik admin tab), and under Debug, set Fabrik debug to "Debug JS", so it loads the uncompressed JS files.

See if that fixes the problem.

The issue is that when duplicating a group, we're setting origId to the full id with the _x repeat count appended, instead of just the base ID without the _x.

-- hugh
 
We are in need of some funding.
More details.

Thank you.
Back
Top