You are viewing limited content. For full access, please sign in.

Question

Question

How to do multiple calculations in a form

asked on August 11, 2014

Hi All,

 

I have a expense report form in which I'm adding up values from different tables and saving the result into a field outside the tables. With the example found in the help files I am able to do this without problems. However, I have a calculation that is not working, which is for getting the gas expense. This should calculated by multiplying the miles ran times a default value. I have added the function to do this, however it will not work on the form. This is the code I'm using:
 

$(document).ready(function () {
    $('.cf-table-block').on('blur', 'input', sumtotal); 
    $('.miles').on('blur', 'input', calcMiles);
    if ($('.subtotal').length > 0) {
        $('.cf-table-block').on('blur', 'input', rowtotal);
    }
     
  
    function sumtotal() {
        var sum = 0;
        $('td.sum').each(function () {
            var s = 0;
            $(this).find('input').each(function () {
                s += parseNumber($(this).val());
            });
            $(this).find('.subtotal input').val(s.toFixed(2));
            $(this).find('.subtotal input').attr('readonly', 'True');
            sum += s;
        });
        $('.total input').val(sum.toFixed(2));
        $('.total input').attr('readonly', 'True');
    }
  
    function rowtotal() {
        var sum = 0;
        
        $('.cf-table-block tbody tr').each(function () {
            var s = 0;
            $(this).find('.sum input').each(function () {
                s += parseNumber($(this).val());
            })                        
            $(this).find('.subtotal input').val(s.toFixed(2));
            $(this).find('.subtotal input').attr('readonly', 'True');
            sum += s;
        });
      
    }
  	
    function calcMiles() {
    var sum = 0;
        
        $('.cf-table-block tbody tr').each(function () {
            var s=1;
            $(this).find('.miles input').each(function () {
                 s *= parseNumber($(this).val());
            })                        
            $(this).find('.subtotal input').val(s.toFixed(2));
            $(this).find('.subtotal input').attr('readonly', 'True');
            sum += s;
        });
    }
 
    function parseNumber(n) {
        var f = parseFloat(n); //Convert to float number.
        return isNaN(f) ? 0 : f; //treat invalid input as 0;
    }
});

Here's a funny thing though:
If I change the trigger for the calcMiles function to this:

 if ($('.miles').length > 0) {
        $('.cf-table-block').on('blur', 'input', calcMiles);
    } 

That particular function works, but the rest of the code doesn't.

 

Any help will be greatly appreciated!

0 0

Answer

SELECTED ANSWER
replied on August 12, 2014 Show version history

I didn't realize those other tables were being included in your calculations. As written, the previous code was not running when those tables changed. For those amount fields, change the CSS class to subtotal instead of sum. Then use this code:

 


 

$(document).ready(function () {
    $('.mileage-total').on('blur', 'input', sumTotal);
    $('.row-subtotal').on('blur', 'input', rowTotal);
    $('.cf-table-block').on('blur','input', calcTotal);

    function sumTotal() {
        var sum = 0;
        var mileageSum = 0;
        $('td.sum').each(function () {
            var s = 0;
            $(this).find('input').each(function () {
                s += parseNumber($(this).val());
            });
            $(this).find('.subtotal input').val(s.toFixed(2));
            sum += s;
        });

        $('.mileage-total tbody tr').each(function () {
            var mileageSubtotal = parseNumber($(this).find('.miles input').val()) * parseNumber($(this).find('.rate input').val());
            $(this).find('.subtotal input').val(mileageSubtotal.toFixed(2));
            mileageSum += mileageSubtotal
        });
    }

    function rowTotal() {
        var sum = 0;
        $('.row-subtotal tbody tr').each(function () {
            var s = 0;
            $(this).find('.sum input').each(function () {
                s += parseNumber($(this).val());
            })
            $(this).find('.subtotal input').val(s.toFixed(2));
            sum += s;
        });
    }

    function calcTotal() {
        var s = 0;
        $('.subtotal input').each(function () {
            s += parseNumber($(this).val());
        });
        $('.total input').val(s.toFixed(2));
    }

    function parseNumber(n) {
        var f = parseFloat(n); //Convert to float number.
        return isNaN(f) ? 0 : f; //treat invalid input as 0;
    }
});

 

1 0

Replies

replied on August 11, 2014

The mile total isn't actually being placed into a field. Add a field to your form and give it the mileTotal class. Try this modified code. I commented on the line where you'll want to adjust the mile calculation.

 

$(document).ready(function () {
    $('.cf-table-block').on('blur', 'input', sumtotal); 
    $('.cf-table-block').on('blur', 'input', calcMiles);
  
  	if ($('.subtotal').length > 0) {
      $('.cf-table-block').on('blur', 'input', rowtotal);
    }
  
    function sumtotal() {
        var sum = 0;
        $('td.sum').each(function () {
            var s = 0;
            $(this).find('input').each(function () {
                s += parseNumber($(this).val());
            });
            $(this).find('.subtotal input').val(s.toFixed(2));
            $(this).find('.subtotal input').attr('readonly', 'True');
            sum += s;
        });
        $('.total input').val(sum.toFixed(2));
        $('.total input').attr('readonly', 'True');
    }
  
  function rowtotal() {
        var sum = 0;
        $('.cf-table-block tbody tr').each(function () {
            var s = 0;
            $(this).find('.sum input').each(function () {
                s += parseNumber($(this).val());
            })
            $(this).find('.subtotal input').val(s);
            sum += s;
        });
    }
  	
    function calcMiles() {
    var sum = 0;
        
        $('.cf-table-block tbody tr').each(function () {
            var s=0;
            $(this).find('.miles input').each(function () {
                 s += parseNumber($(this).val());
            })                        
            sum += s;
        });
      // here's where you can multiple the mile total by some amount
      $('.mileTotal input').val((sum * .45).toFixed(2));
      $('.mileTotal input').attr('readonly', 'True');
    }
 
    function parseNumber(n) {
        var f = parseFloat(n); //Convert to float number.
        return isNaN(f) ? 0 : f; //treat invalid input as 0;
    }
});

 

0 0
replied on August 11, 2014

Hi Eric,

 

Thank you for your reply. I added your line, but strangely any amount I put into my miles field, ends up being totaled to $1.35.

 

Anyhow, the rate would be varying from time to time, and I'm currently reading it off another field which I had also assigned the class miles. Moreover, I need this amount to be added up the grand total, hence why I was still using the subtotal class on that field. I have added the form, in case that helps you get an idea.

 

Thank you.

0 0
replied on August 11, 2014

Thanks for clarifying. I didn't realize you were putting the mileage total in the row. I believe the rowTotal function in the code was interfering with your calcMiles function. I removed it, since it doesn't look like you're using it. Try replacing your code with this:

 

$(document).ready(function () {
    $('.cf-table-block').on('blur', 'input', sumtotal);
    $('.cf-table-block').on('blur', 'input', calcMiles);

    function sumtotal() {
        var sum = 0;
        $('td.sum').each(function () {
            var s = 0;
            $(this).find('input').each(function () {
                s += parseNumber($(this).val());
            });
            $(this).find('.subtotal input').val(s.toFixed(2));
            sum += s;
        });
        $('.total input').val(sum.toFixed(2));
    }

    function calcMiles() {
        $('.cf-table-block tbody tr').each(function () {
            var s = 1;
            $(this).find('.miles input').each(function () {
                s *= parseNumber($(this).val());
            });
            $(this).find('.subtotal input').val(s.toFixed(2));
        });
    }

    function parseNumber(n) {
        var f = parseFloat(n); //Convert to float number.
        return isNaN(f) ? 0 : f; //treat invalid input as 0;
    }
});


Is that what you're looking for? Or do you want the overall total in a field outside of the form?

0 0
replied on August 11, 2014 Show version history

Hi Eric,

 

Yes, we need to add the total on a field outside of the table. 

 

This works for mileage calculation, however it breaks the rest of the code as it won't add up the fields on the first row

 

And it is not adding up the total to the field:

 

That's the same behavior I got before when I changed the trigger to the function :(

0 0
replied on August 11, 2014

Ah, I didn't realize you were using the rowSubtotal function. I did a little reorganization to get things working.

 

Instead of giving your rate column the miles CSS class, give it the rate CSS class. In addition, add the row-subtotal CSS class to the table where you're getting the row-subtotal.

 

Then, try this code.

$(document).ready(function () {
    $('.cf-table-block').on('blur', 'input', sumtotal);
    $('.row-subtotal').on('blur', 'input', rowtotal);

    function sumtotal() {
        var sum = 0;
        var mileageSum = 0;
        $('td.sum').each(function () {
            var s = 0;
            $(this).find('input').each(function () {
                s += parseNumber($(this).val());
            });
            $(this).find('.subtotal input').val(s.toFixed(2));
            sum += s;
        });

        $('.cf-table-block tbody tr').each(function () {
            var mileageSubtotal = parseNumber($(this).find('.miles input').val()) * parseNumber($(this).find('.rate input').val());
            $(this).find('.subtotal input').val(mileageSubtotal.toFixed(2));
            mileageSum += mileageSubtotal
        });

        $('.total input').val(parseNumber(sum.toFixed(2)) + parseNumber(mileageSum.toFixed(2)));
    }

    function rowtotal() {
        var sum = 0;
        $('.row-subtotal tbody tr').each(function () {
            var s = 0;
            $(this).find('.sum input').each(function () {
                s += parseNumber($(this).val());
            })
            $(this).find('.subtotal input').val(s.toFixed(2));
            sum += s;
        });
    }

    function parseNumber(n) {
        var f = parseFloat(n); //Convert to float number.
        return isNaN(f) ? 0 : f; //treat invalid input as 0;
    }
});

 

 


 

1 0
replied on August 11, 2014

Hey Eric,

 

Almost there! Calculations are working beautiful now. We only have one problem: On the table that row subtotal is working, whenever I click on another table, the subtal value gets changed to zero

 

 

The calculations are kept, but it simply loses the value on the field. If I retype one of the sum values in that row, then the subtotal shows up again, until I add a value on another table. 

0 0
replied on August 12, 2014

I think we've got a winner here. One of the issues was that the sumTotal function was running when any table was modified and it was erasing the subtotal in tables that didn't have mileage calculations. So, add the mileage-total class to the table where you calculate mileage and then the code can be more specific.

 

$(document).ready(function () {
    $('.mileage-total').on('blur', 'input', sumTotal);
    $('.row-subtotal').on('blur', 'input', rowTotal);

    function sumTotal() {
        var sum = 0;
        var mileageSum = 0;
        $('td.sum').each(function () {
            var s = 0;
            $(this).find('input').each(function () {
                s += parseNumber($(this).val());
            });
            $(this).find('.subtotal input').val(s.toFixed(2));
            sum += s;
        });

        $('.mileage-total tbody tr').each(function () {
            var mileageSubtotal = parseNumber($(this).find('.miles input').val()) * parseNumber($(this).find('.rate input').val());
            $(this).find('.subtotal input').val(mileageSubtotal.toFixed(2));
            mileageSum += mileageSubtotal
        });

        calcTotal();
    }

    function rowTotal() {
        var sum = 0;
        $('.row-subtotal tbody tr').each(function () {
            var s = 0;
            $(this).find('.sum input').each(function () {
                s += parseNumber($(this).val());
            })
            $(this).find('.subtotal input').val(s.toFixed(2));
            sum += s;
        });
        calcTotal();
    }

    function calcTotal() {
        var s = 0;
        $('.subtotal input').each(function () {
            s += parseNumber($(this).val());
        });
        $('.total input').val(s.toFixed(2));
    }

    function parseNumber(n) {
        var f = parseFloat(n); //Convert to float number.
        return isNaN(f) ? 0 : f; //treat invalid input as 0;
    }
});

 

0 0
replied on August 12, 2014

Hey Eric,

 

Not yet :(. Now it is not adding up the two middle fields as it was doing it before. I had the fields with the sum class. I've tried changing them to the subtotal and even adding the row-subtotal class to the table but it didn't work:

 

The top row and mileage work fine, though.

0 0
replied on August 12, 2014

Are those amount fields being manually entered or are they auto-populated from something else?

SELECTED ANSWER
replied on August 12, 2014 Show version history

I didn't realize those other tables were being included in your calculations. As written, the previous code was not running when those tables changed. For those amount fields, change the CSS class to subtotal instead of sum. Then use this code:

 


 

$(document).ready(function () {
    $('.mileage-total').on('blur', 'input', sumTotal);
    $('.row-subtotal').on('blur', 'input', rowTotal);
    $('.cf-table-block').on('blur','input', calcTotal);

    function sumTotal() {
        var sum = 0;
        var mileageSum = 0;
        $('td.sum').each(function () {
            var s = 0;
            $(this).find('input').each(function () {
                s += parseNumber($(this).val());
            });
            $(this).find('.subtotal input').val(s.toFixed(2));
            sum += s;
        });

        $('.mileage-total tbody tr').each(function () {
            var mileageSubtotal = parseNumber($(this).find('.miles input').val()) * parseNumber($(this).find('.rate input').val());
            $(this).find('.subtotal input').val(mileageSubtotal.toFixed(2));
            mileageSum += mileageSubtotal
        });
    }

    function rowTotal() {
        var sum = 0;
        $('.row-subtotal tbody tr').each(function () {
            var s = 0;
            $(this).find('.sum input').each(function () {
                s += parseNumber($(this).val());
            })
            $(this).find('.subtotal input').val(s.toFixed(2));
            sum += s;
        });
    }

    function calcTotal() {
        var s = 0;
        $('.subtotal input').each(function () {
            s += parseNumber($(this).val());
        });
        $('.total input').val(s.toFixed(2));
    }

    function parseNumber(n) {
        var f = parseFloat(n); //Convert to float number.
        return isNaN(f) ? 0 : f; //treat invalid input as 0;
    }
});

 

1 0
replied on August 12, 2014

Thank you so much Eric! That did the trick. 

 

For reference, this is the final code on my form, making the first total field, the mileage total  and the expense report total read only. Note that I didn't use the field property "read only" as when the form is saved the data in these fields is not stored, even though we're using build 9.1.1.1522. 

 

$(document).ready(function () {
    $('.mileage-total').on('blur', 'input', sumTotal);
    $('.row-subtotal').on('blur', 'input', rowTotal);
    $('.cf-table-block').on('blur','input', calcTotal);

    function sumTotal() {
        var sum = 0;
        var mileageSum = 0;
        $('td.sum').each(function () {
            var s = 0;
            $(this).find('input').each(function () {
                s += parseNumber($(this).val());
            });
            $(this).find('.subtotal input').val(s.toFixed(2));
            sum += s;
        });

        $('.mileage-total tbody tr').each(function () {
            var mileageSubtotal = parseNumber($(this).find('.miles input').val()) * parseNumber($(this).find('.rate input').val());
            $(this).find('.subtotal input').val(mileageSubtotal.toFixed(2));
            $(this).find('.subtotal input').attr('readonly', 'True'); //Makes Mileage "Amount" Read only

          mileageSum += mileageSubtotal
        });
    }

    function rowTotal() {
        var sum = 0;
        $('.row-subtotal tbody tr').each(function () {
            var s = 0;
            $(this).find('.sum input').each(function () {
                s += parseNumber($(this).val());
            })
            $(this).find('.subtotal input').val(s.toFixed(2));            
			$(this).find('.subtotal input').attr('readonly', 'True'); //Makes Detail's "Total" Read only
          sum += s;
        });
    }

    function calcTotal() {
        var s = 0;
        $('.subtotal input').each(function () {
            s += parseNumber($(this).val());
        });
        $('.total input').val(s.toFixed(2));
        $('.total input').attr('readonly', 'True'); //Makes "Expense Report Total" Read only

    }

    function parseNumber(n) {
        var f = parseFloat(n); //Convert to float number.
        return isNaN(f) ? 0 : f; //treat invalid input as 0;
    }
});

 

0 0
replied on August 12, 2014

You're welcome! I'm glad that worked for you. I'm happy people are using the JavaScript examples from the help. If you have any feedback on that documentation, I'd love to hear it.

0 0
You are not allowed to follow up in this post.

Sign in to reply to this post.