0

I'm working on a GPA calculator, but I've hit a road block.

Here's how the calculator looks like: http://codepen.io/m6cheung/pen/KdWGxa.

Here is the JS part of it:

var $units = $('.units');
var $grade = $('.grade-select');
var $gpa = $('#gpa');
var sum = 0;

$('.btn').click(function() {
  $('.block').last().clone().children().val("").parent().appendTo($('.inner-box'));
});

$('.result').hide();

$units.keyup(function() {
  $gpa.text((($grade.val() * $(this).val()) / $(this).val()).toFixed(2));  
});

$grade.change(function() {
    $gpa.text((($units.val() * $(this).val()) / $units.val()).toFixed(2));
    $('.result').show();
});

What I want to know: is there any other way, so I can use jQuery to manipulate further $units and $grade values when I press the Add Course button? For now, it only works for the first set of input values.

3
  • Is that ok for you codepen.io/anon/pen/QjvvXG Commented Oct 6, 2015 at 11:07
  • If it will work as you waited i will write as an answer Commented Oct 6, 2015 at 11:07
  • would this allow me to add and multiply vals between different inputs? Commented Oct 6, 2015 at 11:09

3 Answers 3

2

after adding a new row the keyup and change events are not bind to them.

try using:-

$(document).on('keyup','.units', function() {

and

$(document).on('change','.grade-select', function() {

EDIT from comment

to add them up, create a new function:

function sumScores(){
   var score = 0;
   $('.block').each(function(i, element){
      var unit = $(element).find('.units').val();
      var grade = $(element).find('.grade-select').val();

      // do calculation and add to score

   });

   $gpa.text(score.toFixed(2); 
}

then set that function to the keyup/change handler.

$(document).on('keyup','.units', sumScores);
$(document).on('change','.grade-select', sumScores);
Sign up to request clarification or add additional context in comments.

1 Comment

this is really good, but I also wanted to be able to manipulate the new DOM elements. For example, I wanted to be able to add the input vals together.
1

Since the inputs are added dynamically, you need to bind events to the closest static parent, such as .outer-box. Binding it to document is bad/costly due to event bubbling. Adding up the inputs is as easy as writing a function that would be called on keyup and change which also eliminates code duplication.

 var $oBox = $('.outer-box'),
    $gpa = $('#gpa'),
    $result = $('.result').hide();

$('.btn').click(function() {
    $('.block').last().clone().children().val("").parent().appendTo($('.inner-box'));
});

$oBox.on("keyup", ".units", function() {
    $gpa.text(getTotal());
});

$oBox.on("change", ".grade-select", function() {
    $gpa.text(getTotal());
    //Show $result only if it's  hidden
    $result.is(":hidden") && $result.show();
});

//The function I stated above
function getTotal() {
    var sum = 0;  
    //Loop thru the units
    $('.units').each(function() {
        var $this = $(this);
        //You must also check if the entered unit is a number
        //to avoid operating on non-number inputs
        //https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/isNaN
        if ( !isNaN($this.val()) ) {
            //Input vals are always of type string, so, convert them to numbers
            //Multiply the pairs
            sum += parseFloat($this.val()||0) * parseFloat($this.parent().find('.grade-select').val()||0);
        }
    });
    //Format the number
    return sum.toFixed(2);
}

Your updated pen

Comments

1

I noticed the beginning of your code starts with: var $units = $('.units');

And your inputs are dynamically generated by cloning.

One reason why your computation only works at first input is because $input only points to the fist input, same with $grade.

Maybe you are expecting that $input will automatically take other input as they are cloned. It is not the case. It does not work like CSS rules. You need to re-execute the line for every clone like this:

$('.btn').click(function() {
  $('.block').last().clone().children().val("").parent().appendTo($('.inner-box'));
  $units = $('.units');
  $grade = $('.grade-select');
});

To manipulate all values you need to loop all elements like this:

var sum = 0;
for (var n = 0; n < $units.length; n++) {
    sum += 1 * $($units[n]).val();//1 * -> is for assurance it adding not concat
    //to retreive $grade use $($grade[n]).val()
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.