Reputation: 526
I've asked this question twice before ([1], [2]) and got some good answers, but none of them were quite what I was looking for.
The situation: I have a table, and the cells in one column are contentEditable
. The problem: The editable area does not reach all the edges of the cell. Instead, there is a thin padding (5px) of un-editable area underneath the editable section. I want that 5px of space to stay, but also want it to be editable (i.e. I like the dimensions, but not the un-editable aspects of it).
I am already aware that JavaScript allows for the document.getElementById("id").contentEditable = true;
property to do just this. In fact, I would much prefer to use this method (and if there is a way, please let me know)! However, I am purposely trying to set up an un-editable unit on one end of the cell using <span>
, which ends up getting taken up as input by the script when I need the cells to do a function (e.g. when adding a sum of numbers, the unit gets parsed in with the integers, and the output becomes NaN
).
Visually, what I'm looking for is as shown in this mock-up:
Below is a visual representation of the unnecessary padding (except on the right side), shown in red (I changed the color in the CSS just to make it visible here). To be clear, I still like the dimensions of the cells, but I want to make the entire area of the cell editable, except for where the text "kg" is. Also, the red area to the right of "kg" isn't unnecessary padding, it should remain un-editable.
Additionally, here is the code I have so far:
function myFunction() {
var jack = document.getElementById("jack").innerText;
var john = document.getElementById("john").innerText;
var joe = document.getElementById("joe").innerText;
var total = parseInt(jack) + parseInt(john) + parseInt(joe);
document.getElementById("total").innerHTML = total;
}
myFunction();
* {
box-sizing: border-box;
}
table {
width: 100%;
}
table,
tr,
th,
td {
background-color: #fff;
border: 1px solid black;
border-collapse: collapse;
font-family: Arial, sans-serif;
}
td:last-child {
display: flex;
justify-content: space-between;
align-items: center;
border: none;
}
td:last-child,
span:first-child {
flex-grow: 1;
margin-right: 10px;
outline: none;
text-align: right;
}
.cell {
height: 30px;
}
#total {
display: flex;
justify-content: flex-end;
}
<table>
<thead>
<tr class="cell">
<th>Person</th>
<th>Weight</th>
</tr>
</thead>
<tbody>
<tr class="cell">
<td>Jack</td>
<td id="jack" oninput="myFunction()">
<span contentEditable="true">4000</span>
<span>kg</span>
</td>
</tr>
<tr class="cell">
<td>John</td>
<td id="john" oninput="myFunction()">
<span contentEditable="true">200</span>
<span>kg</span>
</td>
</tr>
<tr class="cell">
<td>Joe</td>
<td id="joe" oninput="myFunction()">
<span contentEditable="true">3</span>
<span>kg</span>
</td>
</tr>
<tr class="cell">
<td>Total</td>
<td>
<span id="total"></span>
<span>kg</span>
</td>
</tr>
</tbody>
</table>
As you can see, on the very corners/edges of the cell on the right column, there is about 5px of un-editable space on the top, bottom, and left side. Is there a way to make this specific part editable without a function receiving the units on the right side of the cell (where the unit is)?
Any help is much appreciated!
Upvotes: 1
Views: 660
Reputation: 451
I used <input />
instead of <span />
for editing (personal preference).
The unit is a span floating on 5px from the right of the cell (Absolute span in a relative div inside a td).
For the input: hide the border, take up 100% width and height, pad about 25px (so the unit will remain on the right of the textbox content).
Also added column width.
function myFunction() {
var jack = document.getElementById("inpJack").value;
var john = document.getElementById("inpJohn").value;
var joe = document.getElementById("inpJoe").value;
var total = parseInt(jack) + parseInt(john) + parseInt(joe);
document.getElementById("total").innerHTML = total;
}
myFunction();
* {
box-sizing: border-box;
}
table {
width: 100%;
}
table,
tr,
th,
td {
background-color: #fff;
border: 1px solid black;
border-collapse: collapse;
font-family: Arial, sans-serif;
}
.cell {
vertical-align: middle;
}
.tdPersonName, .tdHeader {
height: 30px;
padding-left: 5px;
}
.divInputContainer {
position:relative;
}
.withUnit, .inpWithUnit {
text-align: right;
padding-right: 25px;
}
.inpWithUnit {
font-family: Arial, sans-serif;
font-size: 16px;
height: 30px;
width: 100%;
height: 100%;
margin:0;
border: none;
}
.inpWithUnit:focus {
outline-width: 0;
}
.spUnit {
position:absolute; right:5px;
}
#total {
display: flex;
justify-content: flex-end;
}
<table>
<colgroup>
<col style="width: 40%;">
<col style="width: 60%;">
</colgroup>
<thead>
<tr class="cell">
<th class="tdHeader">Person</th>
<th class="tdHeader">Weight</th>
</tr>
</thead>
<tbody>
<tr class="cell">
<td class="tdPersonName">Jack</td>
<td id="jack" oninput="myFunction()">
<div class="divInputContainer">
<span class="spUnit">kg</span>
<input id="inpJack" class="inpWithUnit" value="4000" />
</div>
</td>
</tr>
<tr class="cell">
<td class="tdPersonName">John</td>
<td id="john" oninput="myFunction()">
<div class="divInputContainer">
<span class="spUnit">kg</span>
<input id="inpJohn" class="inpWithUnit" value="200" />
</div>
</td>
</tr>
<tr class="cell">
<td class="tdPersonName">Joe</td>
<td id="joe" oninput="myFunction()">
<div class="divInputContainer">
<span class="spUnit">kg</span>
<input id="inpJoe" class="inpWithUnit" value="3" />
</div>
</td>
</tr>
<tr class="cell">
<td class="tdPersonName">Total</td>
<td>
<div class="divInputContainer">
<span class="spUnit">kg</span>
<span id="total" class="withUnit" />
</div>
</td>
</tr>
</tbody>
</table>
Edit:
We can reduce the space by removing the padding on the cell and textbox, however, still, a little space will remain over and under the text. This is because that's how the font is. The numbers do not take the full top to bottom space. For example, the bottom of 1234 is higher than bottom of 'g' or 'q'.
Upvotes: 1
Reputation: 423
This might help in future too:
While doing css I too get lots of problem like this, and till now the best solution I found is:
If you got any extra styling:
-> Ctrl+Shift+I you will get developer page.
-> Go to Computed tab which is next to Styles Tab
--> Then compare values of style and values you have assign, You will find the solution by yourself.
This is how I find the solution for myself on styling issues afap. Hope it will help you too.
Upvotes: 1
Reputation: 11437
The title you posted which was about calculations differs to your question (which was about presentation).
If you want to keep your current code your can use document.querySelector("#jack span:first-child")
then apply parseInt()
. The issue with the padding is that you are using flexbox on a table cell. To resolve both issues you can use :after
pseudo element and remove the inner spans and display: flex
.
Also, with parseInt
you need to add default values using ||
operator as suggested in other answers.
Here is an example:
function myFunction() {
var jack = document.getElementById("jack").innerText;
var john = document.getElementById("john").innerText;
var joe = document.getElementById("joe").innerText;
var total = (parseInt(jack) || 0) + (parseInt(john) || 0) + (parseInt(joe) || 0);
document.getElementById("total").innerHTML = total;
}
myFunction();
table {
width: 100%;
}
table,
tr,
th,
td {
background-color: #fff;
border: 1px solid black;
border-collapse: collapse;
font-family: Arial, sans-serif;
}
td:last-child {
border: none;
text-align: right;
outline: 0;
}
td:last-child::after {
content: " kg";
}
.cell {
height: 30px;
}
<table>
<thead>
<tr class="cell">
<th>Person</th>
<th>Weight</th>
</tr>
</thead>
<tbody>
<tr class="cell">
<td>Jack</td>
<td id="jack" oninput="myFunction()" contentEditable="true">
3000
</td>
</tr>
<tr class="cell">
<td>John</td>
<td id="john" oninput="myFunction()" contentEditable="true">
200
</td>
</tr>
<tr class="cell">
<td>Joe</td>
<td id="joe" oninput="myFunction()" contentEditable="true">3
</td>
</tr>
<tr class="cell">
<td>Total</td>
<td id="total">
</td>
</tr>
</tbody>
</table>
Upvotes: 2
Reputation: 51
this margin you see on the right caused by flex-box, you can remove
display: flex;
after that, you may notice that the total cell became broken to fix it edit your function like this :
function myFunction() {
var jack = document.getElementById("jack").innerText;
var john = document.getElementById("john").innerText;
var joe = document.getElementById("joe").innerText;
var total = parseInt(jack) + parseInt(john) + parseInt(joe);
document.getElementById("total").innerText = total + " kg";
}
myFunction();
and your HTML :
<td id="total">
<span>0</span>
<span>kg</span>
</td>
Upvotes: 1
Reputation: 10627
Just use padding:0;
, in CSS, where you don't want the padding. You may also want to use *{ box-sizing:border-box; }
, as a best practice, so the padding and borders become part of the width and height of all Elements.
Upvotes: 2