Javascript functions

Hi guys, I am struggling a bit. I am creating a function a calculator type of tool.

the user enters input a percentage, that input is then changed to number, I need to store the number and total all the number once the user inputs have been changed.
example
user enters 7 percentages 85,85,85,85,85,85,85 into 7 textboxes
these percentages are then changed to 7,7,7,7,7,7,7.
I need to total all the 7’s and display it to the user.

function calc(num){
  apsa = 0;

  var num1 = document.getElementById("num1").value;
  
  if ( num1 <=100 && num1 >=90 ) {
    let apsa = 15;
    alert( num1 + "%" +  " = aps score for maths/math lit is:" + apsa ); 
    
    alert(num1 +"%" +  " = score is :" + apsa ); 
  } else if ( num1 <=89 && num1 >=80 ) {
   
    alert(" score  is 13" );
  }
  ...
}

Hi @samodienshameegh54,

Welcome to the forum.

Just to let you know, when typing your code in to the text editor.

function example (x,y) {
  ...
}

If you select and highlight the code then click on the </> button at the top of the editor you can convert it to a code block. This will wrap the text in-between backticks ``` and makes it easier to read.

I’ve formatted your code this time.

It’s my bedtime, but I am sure someone will be along soon to help you :slight_smile:

1 Like

To start off with I would think about writing two functions. One to calculate a percentage of a number and a second function that adds up a collection of numbers.

function percentageOf (percent, number) {
  const percentage = // percentage calculation
  return percentage;
}
function sumOfNumbers (numbers) {
  let total = 0;

  for (let i = 0; i < numbers.length; i+=1) {
     // calculate here
  }

  return total;
}

Things to look at:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions

This can be simplified using Array.reduce() and passing an arrow function.

const sum = numbers.reduce((p, c) => p + c, 0)
  1. p = previous cumulative value
  2. c = current value
  3. 0 = start cumulative value

For managing the percentage conversion rules I would steer you toward a map.

const percentageMap = new Map([
  [15, { min: 90, max: 100 }],
  [13, { min: 80, max: 89 }],
  ...
]);

Thank you. I will make sure to follow the guidelines you have provided :slight_smile:

1 Like

1 .User enters a percentage in the textbox

<input id="num1"  type="textbox" placeholder="please enter marks in percentage" class="textbox"  pattern="^[0-9]*$" >Maths/Maths lit</br><input id="num2"type="textbox" placeholder="please enter marks in percentage" class="textbox" >Home language</br>
  1. Percentage is converted to a score based on a guideline
var num1 = document.getElementById("num1").value;
  if(num1 <=100 && num1 >=90){
   let apsa = 15;
    
    
  alert(num1 +"%" +  " = aps score for maths/math lit is:" + apsa ); 
  } else if ( num1 <=89 && num1 >=80){
   
    alert("aps score for maths/math lit is 13" );
    
  }
  else if ( num1 <=79 && num1 >=70){
    alert("aps score for maths/math lit is 11" );
    
  } else if ( num1 <=69 && num1 >=60){
    alert("aps score for maths/math lit is 9" );
    
  }else if ( num1 <=59 && num1 >=50){
    alert("aps score for maths/math lit is 7" );}
    else if ( num1 <=49 && num1 >=40){
    alert("aps score for maths/math lit is 5" );}
 
  else if ( num1 <=39 && num1 >=30){
    alert("aps score for maths/math lit is 3" );}
  
  else if ( num1 <=29 && num1 >=20){
    alert("aps score for maths/math lit is 1" );}
  
  else if ( num1  < 20){
    alert("aps score for maths/math lit is 0" );}
  
  
  var num2 =document.getElementById("num2").value;

  if(num2 <=100 && num2 >=90){
       let apsa = 15 ;
    
  alert("aps score for Home language/ eng 1st additional language  is:" + apsa );
  } else if ( num2 <=89 && num2 >=80){
    alert(("aps score for Home language/ eng 1st additional language  is 13" ) );
    
  }
  else if (num2 <=79 && num2 >=70){
    alert("aps score for Home language/ eng 1st additional language  is 11" );
    
 } else if ( num2 <=69 && num2 >=60){
    alert("aps score for Home language/ eng 1st additional language  is 9" );
   
  } else if ( num2 <=59 && num2 >=50){
    alert("aps score for Home language/ eng 1st additional language  is 7" );}
    else if ( num2 <=49 && num2 >=40){
    alert("aps score for Home language/ eng 1st additional language  is 5" );}
 
  else if ( num2 <=39 && num2 >=30){
    alert("aps score for Home language/ eng 1st additional language  is 3" );}
  
  else if ( num2 <=29 && num2 >=20){
    alert("aps score for Home language/ eng 1st additional language  is 1");}
  
  else if ( num2  < 20){
    alert("aps score for Home language/ eng 1st additional language  is 0" );}
  
  
  
  
  
  
  1. I want to add up the two scores for example if the user enters 95 and 95, the total will be 30.
my issue is storing the apsa from the if else statement and adding it up and printing it to the user.

I am new to coding and trying to figure this out :sweat_smile:

hi there. thank you for the response. The link below shows what I am trying to do.

@windbeneathmywings

No disrespect to samodienshameegh54, but looking at the given code, what with the ifs and elses I made a judgement call to keep it simple with for loops at this stage.

Sometimes you need to remember what it was like when you had a basic knowledge of coding.

Jumping straight into higher order functions seems maybe a step too far.

@samodienshameegh54

I would still recommend you familiarise yourself with the links I posted. Work on the problem in parts with simple functions one step at a time. That might be easier :slight_smile:

1 Like

yes I agree, break the problem down into smaller chunks. I am definitely going to check those links out! Thanks alot

1 Like

To be fair when I began programming closures didn’t exist within the language being used. Had closures and arrow functions been available like in JavaScript I would consider it a disservice to not introduce them. I think teaching JavaScript like another language say Java is a mistake. If you are going to teach JavaScript teach it right from the beginning using modern advances and language specific features.

Edit: I will leave this post as is, as it may have some value, but please see Archibald’s solution below.

Having a whole long list of ifs and elses is an indication that the code could be improved on — refactored.

The idea is to let the program do the work for you. Looking at your code I can see a pattern.

grade - larger than
15	    >=90
13	    >=80
11	    >=70
9	    >=60
7	    >=50
5	    >=40
3	    >=30
1	    >=20

Minus 2 for the grade, and minus 10 for the score.

So we could use a loop, and we can count backwards with loops e.g.

// for (start; condition to be met; change to i each time)
for (let i = 90; i >= 20; i -= 10) {
    console.log(i); // 90 80 70 60 50 40 30 20
}

That the scores, now for the grades

let currentGrade = 15; // start with the highest

for (let i = 90; i >= 20; i -= 10) {
    console.log(i, currentGrade); // (15, 90) (13, 80)  ... (1, 20)
    currentGrade -= 2; // deduct 2 from grade each time
}

If we add a conditional into that loop we can stop it when it matches a certain score.

let currentGrade = 15; // start with the highest
let gradeAchieved = 0; // a default value

let myScore = 72;

for (let i = 90; i >= 20; i -= 10) {
    if (myScore >= i) { // >= 90 >=80 >=70 etc..
        gradeAchieved = currentGrade; // 15 13 11 etc
        break; // this will break out and stop the loop
    }
    currentGrade -= 2;
}
console.log(gradeAchieved) // 11

Note: If the score isn’t larger than or equal to 20 we don’t get to assign currentGrade to gradeAchieved, so the gradeAchieved stays at 0.

We can now think about putting that into a function to calculate the grade.

function calculateGrade (score) {
    let grade = 15; // starting grade
    let gradeAchieved = 0; // a default grade

    for ( let i = 90; i >= 20; i-=10 ) {
        if (score >= i) {
            gradeAchieved = grade;
            break;
        }
        grade -= 2;
    }

    return gradeAchieved;
}
console.log(calculateGrade(72)) // 11
console.log(calculateGrade(85)) // 13
console.log(calculateGrade(18)) // 0

This can be improved on. Returning from a function e.g. return gradeAchieved immediately exits the function, which means we can do away with the break statement and gradeAchieved.

function calculateGrade (score) {
    let grade = 15;

    for ( let i = 90; i >= 20; i-=10 ) {
        if (score >= i) {
            return grade; // will exit the loop and the function.
        }
        grade -= 2;
    }
    // if score was not larger than or equal to 20 then return here instead with 0.
    return 0
}

This is just one approach. It does have one noticeable drawback, and that is if the grades change, say you need a score of 85 - 90 to score 13 then it falls apart. In that case similar to windbeneathmywings I would look at some sort of map or array.

My approach would be to work out the score directly:

score = 2 * Math.floor(percentage / 10) - 3;
if (score > 15) score = 15;   // when 100%
if (score < 0) score = 0;     // when <20%
2 Likes

Much easier :+1:

I can see how it works, but I would be interest to know what your thought process was to get to that equation?

At the end its easy. If you look at your table you see that the left values are decreasing by 2 while the richt vales are decreasing by 10. So if you divide them by 10 they decrease by 1 and you have to multiply them with 2 to have same steps. Then you just need to shift them to the right value by subtracting 3

1 Like

I think my first step was to spot that integer division (division with integer result) would give integer numbers corresponding to the bands . . . . at least for most of the bands. I was aware that I would have to deal with 100% exam marks and anything under 20% differently.

BTW: I am getting total score for 7 exams with not much extra code. I could post a CodePen but it may be rather confusing for a beginner as it uses an arrow function.

Hi Archibald,

I am trying to wrap my head around everything that has been said.

I thought it would be nice if you could see the calculator.
https://codepen.io/samodienshameegh54/pen/Rwxymwe

I am not surprised :grinning:

At risk of confusing you further, here is my CodePen:

Here’s some explanation of the JavaScript.

Line 1: querySelectorAll gives a collection of elements.
Line 2: Purists around here do not like onclick in the HTML; this does the same thing, in this case the calc() function will be called when the button is clicked.
Line 6: You probably need to read about how forEach works on a collection and how arrow functions work. Anyway this will loop the code lines 7 to 10 for each element. The elements are the seven <input> elements so the percentages are the value attributes of each <input> element.
Line7: This is the mathematics from my previous post but where each element.value will be a percentage from an <input> element.
Line 8: Without this the score for 100% would be 17.
Line 9: Without this scores for 0% to 19% would be negative.
Line 10: Just adding up the 7 scores.
Line 11: Brackets get very confusing with arrow functions :grinning:.
Line 12: Displaying total score.

With virtually every JavaScript calculation I recommend deleting the displayed total as soon as the value in any of the input elements is edited. I have not included code to do this.

I think the regular expression you need is

 /^[1-9][0-9]*$/

The original matches a leading zero number as well as an empty string.

I haven’t been doing very well today with my suggestions.

Just a thought came to mind.

We can use Math.min to find the smallest of two figures e.g.

Math.min(15, 17) // 15

Coversely we can use Math.max to find the largest

Math.max(0, -1) // 0

Put the two together and you can clamp the values between 0 and 15

function clamp (score) {
  return Math.max(Math.min(15, score), 0)
}

clamp(-1) // 0
clamp(17) // 15
score = clamp(2 * Math.floor(percentage / 10) - 3);
1 Like

You can use some built in browser validation.

For instance

<label for='maths'>Maths</label>
<input id='maths' type='number' value='0' min='0' max='100'>

When the user tries to enter an invalid number and clicks submit
validate-input

All without Javascript!

Note: As was pointed out to me, people can still modify settings through the developer tools, but it is a convenience.

I appreciate it maybe a lot to take in, but I have fleshed things out a bit more in this codepen