1

So, a few days ago, I posted this question (nearly identical) and received a very helpful response.

However, in order to make a table calculator, I already have a id set to every table row of a certain column to turn the table into a calculator, which kind of messes up the answer for the original question when I try to apply it for myself (the JavaScript parses the unit "kg" in with the number and displays a sum as "NaN").

As well, there is a visible text box displayed inside of every cell with the answer above, which looks kind of ugly. My current code has cells that don't appear as text boxes but are still editable, which makes for a much sleeker experience in my opinion (I know it makes no functional difference, but the appearance is something that bugs me a lot!)

Below is a mock-up of what I'd like the code to look like. I'm trying to make the numbers/input appear on the right side of the text box, but still on the left side of the unit ("kg").

Below is a mock-up of what I am trying to create (except the numbers would be on the right).

Updated mock-up

Here is the code I have:

<head>
  <style>
    table {
      border: 1px solid black;
      border-collapse: collapse;
      font-family: Arial, sans-serif;
      margin: 5px;
      width: 100%;
    }
    
    th, td {
      border: 1px solid black;
      border-collapse: collapse;
      font-family: Arial, sans-serif;
      margin: 5px;
      padding: 5px;
    }
  </style> 
</head>
<body>
  <table>
    <tr>
      <th>header1</th>
      <th>header2</th>
    </tr>
    <tr>
      <td>entry1</td>
      <td id="entry1" oninput="myFunction()">4000</td>
    </tr> 
    <tr>
      <td>entry2</td>
      <td id="entry2" oninput="myFunction()">200</td>
    </tr>
    <tr>
      <td>Total</td>
      <td id="total"></td>
    </tr>
  </table> 
      
  <script type="text/javascript">
    document.getElementById("entry1").contentEditable = true;
    document.getElementById("entry2").contentEditable = true;
      
    function myFunction()  {
      var entry1 = document.getElementById("entry1").innerText;
      var entry2 = document.getElementById("entry2").innerText;
      
      var total2 = parseInt(entry1) + parseInt(entry2);
      
      document.getElementById("total").innerHTML = total2;
    }
      
      myFunction();
  </script>  
</body>     

As you can see, it adds up the numbers in the right column and displays a sum in the final row. However, I would like units to display here (e.g. "kg") on the side, that aren't editable and, more importantly, don't get parsed as a number in the JavaScript function. Would be great if the ugly textbox outline doesn't appear inside the cell, too.

Is this possible? Any answers appreciated!

ttoshiro
  • 466
  • 5
  • 21
  • [Off-topic]: you should also make your contenteditable thing [single-line](https://stackoverflow.com/q/6831482/8376184) – FZs Jun 09 '20 at 06:10

2 Answers2

1

You get NaN when you call parseInt on an empty string. To fix this, change following statement from

var total = parseInt(jack2) + parseInt(john2) + parseInt (joe2);

to

var total = (parseInt(jack2) || 0) + (parseInt(john2) || 0) + (parseInt (joe2) || 0);

and to display the unit alongside the number in the right column, add 2 span elements inside the td element and use flexbox to align them properly.

To make the number editable, add contentEditable attribute on the span element containing the number. span element containing the unit will be non-editable by default.

function myFunction() {
  var jack2 = document.getElementById("jack").innerText;
  var john2 = document.getElementById("john").innerText;
  var joe2 = document.getElementById("joe").innerText;

  var total = (parseInt(jack2) || 0) + (parseInt(john2) || 0) + (parseInt(joe2) || 0);

  document.getElementById("total").innerHTML = total;
}

myFunction();
table {
  width: 100%;
}

table,
tr,
th,
td {
  border: 1px solid black;
  border-collapse: collapse;
  font-family: Arial, sans-serif;
  margin: 5px;
}

th,
td {
  padding: 5px;
}

td:last-child {
  display: flex;
  justify-content: space-between;
  border: none;
}

td:last-child span:first-child {
  flex-grow: 1;
  margin-right: 10px;
  outline: none;
  text-align: right;
}

#total {
  display: flex;
  justify-content: flex-end;
}
<table>
  <thead>
    <tr>
      <th>Person</th>
      <th>Weight</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Jack</td>
      <td id="jack" oninput="myFunction()">
        <span contentEditable="true">4</span>
        <span>Kg</span>
      </td>
    </tr>
    <tr>
      <td>John</td>
      <td id="john" oninput="myFunction()">
        <span contentEditable="true">2</span>
        <span>Kg</span>
      </td>
    </tr>
    <tr>
      <td>Joe</td>
      <td id="joe" oninput="myFunction()">
        <span contentEditable="true">3</span>
        <span>Kg</span>
      </td>
    </tr>
    <tr>
      <td>Total</td>
      <td id="total"></td>
    </tr>
  </tbody>
</table>
Yousaf
  • 27,861
  • 6
  • 44
  • 69
  • Thanks for your response. I like this design (editable with no visible text box), but is there a way to make the number begin from the right side? – ttoshiro Jun 09 '20 at 00:17
  • Thank you. What is the difference between `td:child` and `#total`? Aren't they the same thing? – ttoshiro Jun 12 '20 at 10:09
  • 1
    you mean difference between `td:last-child` and `#total`, right? `td:last-child` will select all `td` elements that are last child of their parent element whereas `#target` will just select the element with the id `target`. – Yousaf Jun 12 '20 at 10:12
1

To avoid the result being "NAN", an if is added and we check the one of the seals is empty '' and replace it with a 0. In the edit cell two divs are added one to edit the value and the other to add the text "kg".

<style>
      table {
        border: 1px solid black;
        border-collapse: collapse;
        font-family: Arial, sans-serif;
        margin: 5px;
        width: 100%;
      }

      th, td {
        border: 1px solid black;
        border-collapse: collapse;
        font-family: Arial, sans-serif;
        margin: 5px;
        padding: 5px;
      }
      .input_{
          width: 90%;
          float: left;
      }
      .peso{
          width: 10%;
          float: right;
      }
    </style>
    <table>
      <tr>
        <th>Person</th>
        <th>Weight</th>
      </tr>
      <tr>
        <td>Jack</td>
        <td>
            <div class="input_" id="jack" oninput="myFunction()">1</div>
            <div class="peso">kg</div>
        </td>
      </tr> 
      <tr>
        <td>John</td>
        <td>
            <div class="input_" id="john" oninput="myFunction()">2</div>
            <div class="peso">kg</div>
        </td>
      </tr>
      <tr>
        <td>Joe</td>
        <td>
            <div class="input_" id="joe" oninput="myFunction()">3</div>
            <div class="peso">kg</div>
        </td>
      </tr>
      <tr>
        <td>Total</td>
        <td id="total"></td>
      </tr>
    </table> 

    <script type="text/javascript">
      document.getElementById("jack").contentEditable = true;
      document.getElementById("john").contentEditable = true;
      document.getElementById("joe").contentEditable = true;

      function myFunction()  {
        var jack2 = document.getElementById("jack").innerText;
        var john2 = document.getElementById("john").innerText;
        var joe2 = document.getElementById("joe").innerText;
        if(jack2==""){
            jack2=0;
        }
        if(john2==""){
            john2=0;
        }
        if(joe2==""){
            joe2=0;
        }
        var total2 = parseInt(jack2) + parseInt(john2) + parseInt (joe2);

        document.getElementById("total").innerHTML = total2+" kg";
      }

        myFunction();
    </script>
Jairo Rodriguez
  • 356
  • 2
  • 7
  • Thank you for your response. Is it possible to display the numbers (_input) on the right side, but still to the left of "kg"? If so, how? – ttoshiro Jun 09 '20 at 00:12
  • yes , in the class style "input_" add "text-align: end;". and in the kg div " " for a space – Jairo Rodriguez Jun 09 '20 at 16:38