Skip to content Skip to sidebar Skip to footer

How Can I Keep Fraction Formatting Using Javascript?

My code is focused on cooking (Banana Bread recipe). Depending on the number of people, I will sometimes make two Banana Bread's as opposed to one. Thus, I use the selection tool t

Solution 1:

Instead of assigning values a, b, c to the options 1, 2, 3, just use the latter value: it is more intuitive. You can directly use that value for the multiplication instead of doing three different if blocks. You can also do away with the button, since you could just respond to the change in the select-list.

For the particular display of fractions, I would suggest putting all that logic in a class, which you could call Rational. It would keep numerator and denominator separate and allow to do multiplication (and other operations) on it, and to display the result with the desired output format. This way you isolate that formatting logic from the recipe logic.

Here is such a Rational class: it could be easily extended to do more than multiplication (e.g. addition, division, negation, inversion, ...):

constgcd = (a, b) => b ? gcd(b, a % b) : a;

classRational {
    constructor(num, denom = 1) {
        if (num % 1 || denom % 1) throw"Rational constructor should get integer value(s)";
        this.num = num * Math.sign(denom);
        this.denom = Math.abs(denom);
    }
    mul(b) {
        if (typeof b === "number") b = newRational(b);
        const denom1 = gcd(this.denom, b.num);
        const denom2 = gcd(this.num, b.denom);
        returnnewRational((this.num / denom2) * (b.num / denom1), (this.denom / denom1) * (b.denom / denom2));
    }
    toString() {
        const sgn = this.num < 0 ? "-" : "";
        const n = Math.abs(this.num);
        const i = Math.trunc(n / this.denom);
        const rem = (n % this.denom);
        const frac = rem ? rem + "/" + this.denom : "";
        const remainder = {
            "1/2": "½", "1/3": "⅓", "2/3": "⅔", "1/4": "¼", "3/4": "¾",
            "1/5": "⅕", "2/5": "⅖", "3/5": "⅗", "4/5": "⅘",
            "1/6": "⅙", "5/6": "⅚", "1/7": "⅐", "1/8": "⅛",
            "3/8": "⅜", "5/8": "⅝", "7/8": "⅞", "1/9": "⅑", "1/10": "⅒"
        }[frac] || frac && ((i ? "+" : "") + frac);
        return sgn + (i || !remainder ? i : "") + remainder;
    }
}

document.getElementById("quantity").addEventListener("change", onSelectionChange);
var n1 = newRational(2);
var n2 = newRational(1, 2);

functiononSelectionChange() {
    var selection = +document.getElementById("quantity").value;
    document.getElementById('amount').textContent = n1.mul(selection);
    document.getElementById('amount2').textContent = n2.mul(selection);
}
<label>How many Banana Bread's are you making?</label><!-- Selection --><selectid="quantity"><option>1</option><option>2</option><option>3</option></select><br><br><!-- HTML Recipe --><p>
    Step 1: Add 
    <spanid="amount">2</span> cups flour and 
    <spanid="amount2">&frac12;</span> tsp salt into a large, dry bowl.
</p>

Notice how the last function can concentrate on the recipe logic, delegating the use of fractions to the Rational class, which in turn is completely ignorant of the recipe-business.

For older JS engines...

As you comment about an error that may be related to a JS engine that does not support ES6 syntax, I add here a version of the same using old-ES3 syntax:

functiongcd (a, b) {
    return b ? gcd(b, a % b) : a;
}

functionRational(num, denom) {
    if (!denom) denom = 1;
    if (num % 1 || denom % 1) throw"Rational constructor should get integer value(s)";
    this.num = num * Math.sign(denom);
    this.denom = Math.abs(denom);
}

Rational.prototype.mul = function (b) {
    if (typeof b === "number") b = newRational(b);
    var denom1 = gcd(this.denom, b.num);
    var denom2 = gcd(this.num, b.denom);
    returnnewRational((this.num / denom2) * (b.num / denom1), (this.denom / denom1) * (b.denom / denom2));
}
Rational.prototype.toString = function () {
    var sgn = this.num < 0 ? "-" : "";
    var n = Math.abs(this.num);
    var i = Math.floor(n / this.denom);
    var rem = (n % this.denom);
    var frac = rem ? rem + "/" + this.denom : "";
    var remainder = {
        "1/2": "½", "1/3": "⅓", "2/3": "⅔", "1/4": "¼", "3/4": "¾",
        "1/5": "⅕", "2/5": "⅖", "3/5": "⅗", "4/5": "⅘",
        "1/6": "⅙", "5/6": "⅚", "1/7": "⅐", "1/8": "⅛",
        "3/8": "⅜", "5/8": "⅝", "7/8": "⅞", "1/9": "⅑", "1/10": "⅒"
    }[frac] || frac && ((i ? "+" : "") + frac);
    return sgn + (i || !remainder ? i : "") + remainder;
}

document.getElementById("quantity").addEventListener("change", onSelectionChange);
var n1 = newRational(2);
var n2 = newRational(1, 2);

functiononSelectionChange() {
    var selection = +document.getElementById("quantity").value;
    document.getElementById('amount').textContent = n1.mul(selection);
    document.getElementById('amount2').textContent = n2.mul(selection);
}
<label>How many Banana Bread's are you making?</label><!-- Selection --><selectid="quantity"><option>1</option><option>2</option><option>3</option></select><br><br><!-- HTML Recipe --><p>
    Step 1: Add 
    <spanid="amount">2</span> cups flour and 
    <spanid="amount2">&frac12;</span> tsp salt into a large, dry bowl.
</p>

Solution 2:

...

    amount = Math.floor(numerator) + '/' + Math.floor(denominator);
    //EDITswitch (amount) {
        case'1/4':
            amount = '&frac14;';
        break;
        case'1/3':
            amount = '&‌#8531;';
        break;
        case'1/2':
            amount = '&frac12;';
        break;
        case'2/3':
            amount = '&‌#8532;';
        break;
        case'3/4':
            amount = '&frac34;';
        break;
        default:
            amount = amount;
        break;
    }
    //END OF EDITif ( base ) {
        amount = base + ' ' + amount;
    }
    return amount;

Solution 3:

To representate 0.5 as a fraction you're using the html entity &frac12;. The numberToFraction() function is actually returning a string like "1/2" though.

So you need to include a check if amount is 1/2 and in case it is replace it by &frac12; and return this instead.

Furthermore to update the span's you need to use their .innerHTML property instead of .innerText - otherwise you won't see a fraction.

Here's an example:

document.getElementById("button").addEventListener("click", onButtonClick);

functiononButtonClick() {
  document.getElementById("amount").innerText = 2;
  document.getElementById("amount2").innerText = 1 / 2;
  var n1 = document.getElementById("amount").innerText;
  var n2 = document.getElementById("amount2").innerText;
  var selection = document.getElementById("quantity").value;

  if (selection === 'a') {
    document.getElementById('amount').innerText = n1;
    document.getElementById('amount2').innerHTML = numberToFraction(n2);
  }

  if (selection === 'b') {
    document.getElementById('amount').innerText = n1 * 2;
    document.getElementById('amount2').innerHTML = n2 * 2;
  }

  if (selection === 'c') {
    document.getElementById('amount').innerText = n1 * 3;
    document.getElementById('amount2').innerHTML = numberToFraction(n2 * 3)
  }
}

var numberToFraction = function(amount) {
  // This is a whole number and doesn't need modification.if (parseFloat(amount) === parseInt(amount)) {
    return amount;
  }
  // Next 12 lines are cribbed from https://stackoverflow.com/a/23575406.var gcd = function(a, b) {
    if (b < 0.0000001) {
      return a;
    }
    returngcd(b, Math.floor(a % b));
  };
  var len = amount.toString().length - 2;
  var denominator = Math.pow(10, len);
  var numerator = amount * denominator;
  var divisor = gcd(numerator, denominator);
  numerator /= divisor;
  denominator /= divisor;
  var base = 0;
  // In a scenario like 3/2, convert to 1 1/2// by pulling out the base number and reducing the numerator.if (numerator > denominator) {
    base = Math.floor(numerator / denominator);
    numerator -= base * denominator;
  }
  amount = Math.floor(numerator) + '/' + Math.floor(denominator);
  if (amount == "1/2") {
    amount = "&frac12;"
  }
  if (base) {
    amount = base + ' ' + amount;
  }

  return amount;
};
<label> How many Banana Bread's are you making? </label><!-- Selection --><selectid="quantity"><optionvalue="a">1</option><optionvalue="b">2</option><optionvalue="c">3</option></select><br><br><!-- Button --><buttonid="button"type="button">Let's get started!</button><br><br><!-- HTML Recipe --><p>

  Step 1: Add
  <spanid="amount">2</span> cups flour and
  <spanid="amount2"> &frac12;</span> tsp salt into a large, dry bowl.
</p>

Post a Comment for "How Can I Keep Fraction Formatting Using Javascript?"