'bold tags don't take effect in span element in html

I'm totally new to html, css and javascript.

I'm trying to create a simple interest rate calculator and I want to style the result so that the numbers in the result message are highlighted like this:

Interest : If you deposit 10,
at an interest rate of 10.25.
You will receive an amount of 11.025,
in the year 2023.

What I get is the <b> elements rendered as text, for example:

Interest : If you deposit <b>10</b>,
at an interest rate of <b>10.25</b>.
You will receive an amount of <b>11.025</b>,
in the year <b>2023</b>.

My code is this:

function compute()
{
    var principal = document.getElementById("principal").value;
    var rate      = document.getElementById("rate").value;
    var years     = document.getElementById("years").value;
    var interest  = principal * (rate / 100) * years;
    // add amount to principal
    let amount    = interest + parseInt(principal);
    var year      = new Date().getFullYear() + parseInt(years);

    var interestString = "If you deposit " + principal.bold() + ",\n at an interest rate of " + rate + ".\n You will receive an amount of " + amount + ",\n in the year " + year + ".";
    document.getElementById("result").innerText = interestString
}
body {
    background-color:black;
    font-family: arial;
    color:white
}

h1 {
    color: grey;
    font-family: verdana
}

.maindiv {
    background-color: white;
    color:black;
    width:300px;
    padding: 20px;
    border-radius: 25px;
    margin: auto;
}
<div class="maindiv">
    <h1>Simple Interest Calculator</h1>
    Amount <input type="number"  id="principal">  
    <br/>
    Rate <input type="range" id="rate" min="1" max="20" step="0.25" value="10.25"  oninput="this.nextElementSibling.value = this.value">
    <output>10.25</output>   
    <br/>
    No. of Years 
    <select id="years">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
        <option value="4">4</option>
    </select>
    <button onclick="compute()">Compute Interest</button>
    <br>
    <br>
    Interest : <span id="result"></span>
</div>

I would be happy for a way to solve this. Thank you!



Solution 1:[1]

Change innerText to innerHTML.

Solution 2:[2]

  • The String.prototype.bold() method (which wraps any JavaScript string value in a <b> element) is deprecated and should not be used - unless you suddenly found yourself time-warped back to 1995.
  • Instead, I recommend making your "template" into normal HTML, and use <output> elements as placeholders, and use CSS to make all <output> elements bold.

Something like this:

  • My code uses Intl.NumberFormat to format monetary-amounts and percentages appropriately
    • When formatting percentages, remember that number percentage values have to be normalized to 0-1.0; so 10% is 0.1 and 250% is 2.5, and 1.25% is 0.0125.
  • Because JavaScript doesn't have compile-time (or parse-time) type-checking, my code employs defensive-programming techniques to preemptively fast-fail if anything goes wrong by doing throw new Error, including:
    • Verifying that HTML elements referenced by getElementById or querySelector actually exist (with function getElement).
    • Precondition validation that verifies parameter argument value types and other value things (e.g. numeric range bounds-checking).
    • JSDoc (/** @param */, etc) is used to document parameter types in a machine-readable format.
  • I cleaned-up the HTML and wrapped related form fields in <div class="field">) and added a currency-symbol to the <input id="principal" /> field.

const fmtUsd  = new Intl.NumberFormat( 'en-US', { style: 'currency', currency: 'USD' } );
const fmtPerc = new Intl.NumberFormat( 'en-US', { style: 'percent', minimumFractionDigits: 2, maximumFractionDigits: 2 } );

function compute( e ) {

  const errorOutput     = getElement( 'errorOutput'    , 'div' );
  const outputContainer = getElement( 'outputContainer', 'div' );
  
  try {
    
    const principalInput = getElement( 'principal', 'input[type="number"]' );
    const rateInput      = getElement( 'rate'     , 'input[type="range"]' );
    const yearsSelect    = getElement( 'years'    , 'select' );
    
    const principalAmount = getNumberValue( principalInput );
    const ratePercDbl     = getNumberValue( rateInput ) / 100.0;
    const yearsCount      = getNumberValue( yearsSelect );
    
    computeInner( principalAmount, ratePercDbl, yearsCount );
    
    // No errors, so show the output div and hide any previous error messages:
    outputContainer.hidden = false;
    errorOutput    .hidden = true;
  }
  catch( err ) {
    // Something went wrong! So hide the normal output <div> and show the error details:
    errorOutput.hidden = false;
    errorOutput.textContent = ( err || "(Unknown error)" ).toString() + "\r\n\r\n" + ( err.stack );
    outputContainer.hidden = true;
  }
}

/**
 * @param {number} principalAmount
 * @param {number} interestRatePerc
 * @param {number} yearsCount
 */
function computeInner( principalAmount, interestRatePerc, yearsCount ) {

  // Preconditions:
  if( typeof principalAmount != 'number' ) throw new Error( "Expected `principalAmount` to be `number` but encountered " + typeof principalAmount );
  if( typeof interestRatePerc != 'number' ) throw new Error( "Expected `interestRatePerc` to be `number` but encountered " + typeof interestRatePerc );
  if( typeof yearsCount != 'number' || yearsCount <= 0 ) throw new Error( "Expected `yearsCount` to be a positive `number` but encountered " + ( typeof yearsCount ) + " \"" + yearsCount.toString() + "\" instead." );
  
  //
  
  const interest    = principalAmount * interestRatePerc * yearsCount;
  const totalAmount = interest + principalAmount;
  const endYear     = new Date().getFullYear() + yearsCount;
  
  //
  
  setOutput( 'principal', principalAmount , fmtUsd  );
  setOutput( 'rate'     , interestRatePerc, fmtPerc );
  setOutput( 'years'    , endYear                   );
  
  const amountOut = getElement( 'receiveAmountOut', 'output' );
  amountOut.value = fmtUsd.format( totalAmount );
}

/**
 * @param {string} outputFor
 * @param {number} value
 * @param {Intl.NumberFormat} formatter
 */
function setOutput( outputFor, value, formatter ) {
   
  const formattedValue = formatter ? ( formatter.format( value ) ) : ( value.toString() );
   
  const selector = 'output[for~="' + CSS.escape( outputFor ) +'"]';
  const outputs  = document.querySelectorAll( selector );
  for( const outputEl of outputs ) {
    outputEl.value = formattedValue;
  }
}

/**
 * @param {string} id
 * @param {string} validationSelector
 * @returns {HTMLElement}
 */
function getElement( id, validationSelector ) {
  const el = document.getElementById( id );
  if( el === null ) throw new Error( "No element with `id=\"" + id + "\"` was found." );
  if( !el.matches( validationSelector ) ) throw new Error( "The element with `id=\"" + id + "\"` does not match selector \"" + validationSelector + "\"." );
   
  return el;
}

/**
 * @param {HTMLInputElement | HTMLSelectElement} input
 * @returns {number}
 */
function getNumberValue( input ) {
   
  // Preconditions:
  if( !( input instanceof HTMLElement ) ) throw new Error( 'Expected `input` to be a HTML element.' );
  if( !( input.tagName === 'SELECT' || input.tagName === 'INPUT' ) ) throw new Error( 'Expected `input` to be a HTML <input /> or <select> element.' );
   
   //
   
  let valueNumber;
  if( input.tagName === 'SELECT' ) {
     valueNumber = parseInt( input.value, /*radix:*/ 10 );
  }
  else if( input.type === 'number' ) { // Can't use valueAsNumber with type="range", grr.
     valueNumber = input.valueAsNumber;
  }
  else {
     valueNumber = parseFloat( input.value );
  }
   
  if( isNaN( valueNumber ) ) {
    throw new Error( "Form <input> or <select> has invalid value: \"" + input.value + "\"." );
   }
   
   return valueNumber;
}
body {
    background-color: black;
    font-family: sans-serif;
    color: white
}
.maindiv {
    background-color: white;
    color: black;
    width: 300px;
    padding: 20px;
    border-radius: 25px;
    margin: auto;
}

h1 {
    color: grey;
    font-family: verdana
}

.field {
  padding: 1em;
  margin: 1em 0;
  background-color: #eee;
  border-radius: 5px;
}
  .field > label,
  .field > input,
  .field > div > input {
    display: block;
  }

#principalField.field > div {
  display: flex;
  justify-content: stretch;
  align-items: stretch;
}
  #principalField.field > div > span.symbol {
    display: inline-block;
    
    /* Width is 1em with negative right margin of -1.5em to make the currency symbol appear "inside" the <input />. Also, identical font-size, padding and border as Chrome's default style for <input />: */
    width: 1em;
    margin: 0 -1.5em 0 0;
    border: 1px solid transparent;
    padding: 1px 2px;
    z-index: 10;
    
    pointer-events: none;
    user-select: none;
    color: #999;
    font-size: 90%;
  }


#errorOutput {
  border: 1px solid red;
  border-radius: 7px;
  white-space: pre-line;
}

output {
  font-weight: bold;
}
output:empty {
  display: none;
}

input[type="number"] {
  text-align: right;
}
<div class="maindiv">

    <h1>Simple Interest Calculator</h1>
    
    <div class="field" id="principalField">
      <label for="principal">Principal amount</label>
      <div>
        <span class="symbol">$</span>
        <input type="number" id="principal" oninput="compute(event)" value="123.00" size="6" />
      </div>
    </div>
    
    <div class="field">
      <label for="rate">Interest rate (<output for="rate">10.25%</output>)</label>
      <input type="range" id="rate" min="1" max="20" step="0.25" value="10.25" oninput="compute(event)" />
    </div>
    
    <div class="field">
      <label for="years">No. of Years </label>
      <select id="years" oninput="compute(event)">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
        <option value="4">4</option>
      </select>
    </div>
    
    <button hidden type="button" onclick="compute(event)">Compute Interest</button>
    
    <div id="outputContainer" hidden>
    
        If you deposit <output for="principal"></output>
        at an interest rate of <output for="rate"></output>
        you will receive an amount of <output id="receiveAmountOut"></output> in the year <output for="years"></output>.
    
    </div>
    <div id="errorOutput" hidden></div>
    
</div>

Solution 3:[3]

You can change the interestString to this

  var interestString = `If you deposit  <b>${principal}</b>,<br>
  at aninterest rate of <b>${rate}</b>.<br>
  You will receive an amount of <b>${amount}</b>,<br>
  in the year <b>${year}</b>.`;
  
  document.getElementById("result").innerHTML=interestString

and use innerHTML instead of innerText and it will look exactly like the example you gave above!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Adam Orłowski
Solution 2
Solution 3