I am storing the html for a table in $scheduletext. I want to be able to edit any cell of the table when clicking it so I am using JQuery for the on click action. When I click on a cell it goes blank but will not allow me to type in it, what do I need to change to be able to type into this?
<html>
<body>
<div id="main">
<?php
print_r($scheduletext);
?>
</div>
<script type="text/javascript">
$('td').click(function(){
$(this).html("<contenteditable>");
});
</script>
</body>
</html>
For editing and testing purposes, since to run my code you also need the table, the CSS doesnt hurt either... I dumped it into JSfiddle to hopefully make it easier for anyone trying to give me a hand : https://jsfiddle.net/4yczepsj/
Thanks in advance!!
EDIT: For some reason JSfiddle doesnt do anything at all when clicked on, but on the live model on my site the cell goes blank when clicked, but nothing can be entered.
In calling .html("<contenteditable>") you're modifying the inner HTML of your td element to contain a <contenteditable> element (which isn't valid). What you actually want to do is set the contenteditable property:
$(this).prop('contenteditable', true);
contentEditable is an attribute.
Try this :
$(this).attr('contentEditable', true);
Content Editable is an attribute, not an element. You want to add the attribute contenteditable to the the elements you want to have editable content.
$('td').click(function(){
$(this).attr("contenteditable");
});
https://jsfiddle.net/4yczepsj/1/
$('table').on('mousedown', 'td', function (event) {
$(event.target).closest('td').prop("contentEditable", true);
});
NOTE this includes information that the other answers contain, credit to them, but I am adding a little bit more and putting it all on one place.
I made the following changes:
added tabindex so table cells are tabable.
give focus to the table cell on click.
add contenteditable attribute on focus.
select contents of table cell on focus.
remove contenteditable on blur(when the td loses focus).
function setSelection(element) {
// code for selection from http://stackoverflow.com/questions/3805852/select-all-text-in-contenteditable-div-when-it-focus-click#answer-3806004
setTimeout(function() {
var sel, range;
if (window.getSelection && document.createRange) {
range = document.createRange();
range.selectNodeContents(element);
sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (document.body.createTextRange) {
range = document.body.createTextRange();
range.moveToElementText(element);
range.select();
}
}, 0)
}
// add tabindex to all tds.
$('td').attr('tabindex', 0);
$('td').on('focus', function() {
$(this).attr('contenteditable', true);
setSelection(this);
}).on('blur', function() {
$(this).attr('contenteditable', false);
})
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
font-size: 90%;
}
th,
td {
padding: 8px;
}
td {
text-align: center;
}
table {
margin: 0 auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<div id="main">
<table>
<tr>
<th></th>
<th>22oz Dark</th>
<th>12ct 4oz Dark</th>
</tr>
<tr>
<th>2016-01-01</th>
<td>9785</td>
<td>2478</td>
</tr>
<tr>
<th>2016-01-02</th>
<td>8754</td>
<td>2136</td>
</tr>
<tr>
<th>2016-01-03</th>
<td>13587</td>
<td>2203</td>
</tr>
<tr>
<th>2016-01-04</th>
<td>14111</td>
<td>3297</td>
</tr>
<tr>
<th>2016-01-05</th>
<td>13212</td>
<td>3101</td>
</tr>
<tr>
<th>2016-01-06</th>
<td>16335</td>
<td>3299</td>
</tr>
<tr>
<th>2016-01-07</th>
<td>15421</td>
<td>3100</td>
</tr>
</table>
</div>
</body>
</html>
Related
I have a two columned HTML table which I want to translate from English to Greek.
I desire to do that by double-clicking the Click to translate placeholder under the Greek column and then being prompted there, to insert a Greek text instead it.
In other words, I would interact with the HTML file to translate where the placeholder, right from web browser.
Any such (raw data) change should saved in the HTML file directly, without involving database programs such as a MySQL; thus, this program is aimed to be HTML-CSS-JS only.
table, th, td {
border: 1px solid black;
}
<!DOCTYPE html>
<html>
<body>
<section class="allEnglishSections">
<h2>Conditioning</h2>
<table>
<tr><th>English</th><th>Greek</th></tr>
<tr><td>if</td><td class="changeable">Click to translate</td></tr>
<tr><td>than</td><td class="changeable">Click to translate</td></tr>
<tr><td>else</td><td class="changeable">Click to translate</td></tr>
</table>
</section>
<script>
</script>
</body>
</html>
From searching data on how to achieve this, I understand I should use something similar to this pseudocode:
document.querySelectorAll(".changeable").addEventListener(ondblclick, function() {
myTranslation = prompt();
document.querySelector(".changeable").value = myTranslation;
}
But it is unclear to me how to actually selecting all text of a cell by double clicking it, and then changing it directly from web browser in such a way that the HTML file would change.
Is this even possible with latest ECMAScript and if so how will you achieve this?
An easy system would be to create a textarea inside the HTML on double click, and whenever you experience either the blur event or a specific key combination to remove the textarea and swapping it with a text node of it's own value.
Please note that I am added the events onto the tbody element. This is done because most events bubble up, and this way no matter how many <tr> elements get added in dynamically, I will have the same functionality without having to loop over the nodelist and add the event one-by-one.
I also use focusout instead of blur for a similar reason: blur does not bubble up, but focusout does.
Note The current version using the localStorage won't work on StackOverflow due to sandboxed permissions and so on. Copy/Paste the values into something like JSFiddle or Codepen to see a working example. I personally tested it on this JSFiddle in case you want to look at it.
I also did not use an example with AJAX/XHR as you seem relatively new to Javascript, and that needs for you to look up how REST APIs / XHR work. Feel free to make another question once you've done some fiddling with those, but for now that felt a bit out-of-scope for this question.
// get items from storage. if nothing is there originally we will get a null value
const fromStorage = localStorage.getItem('definitions');
// null values are falsey, so if it is null we need to use our default.
// otherwise we just JSON.parse the values we retrieved
const definitions = !fromStorage ? {
"if": null,
"when": null,
"tomato": null,
} : JSON.parse(fromStorage);
// I don't feel like running this command everytime I need to reference the tbody,
// thus, the reference to it here.
const tbody = document.querySelector('#definitions');
// adding an event listener on the tbody means that any of the same event that bubble up from it's children will reach here.
// This means you can add children in dynamically without needing to worry so long as they have
// a data-editorShown attribute
tbody.addEventListener('dblclick', e => {
const parent = e.target.parentElement;
// if somehow the event gets called from something that is NOT one of the TDs, we don't need to go any further from there.
// sidenote, all values in the Element.dataset are read as strings. you can set them to be whatever
// but when you read them, they will be strings.
if (parent.tagName !== 'TR' || parent.dataset.editorShown === 'true') return;
// The editor is now shown, so let's set that
parent.dataset.editorShown = true;
// get the last TD, which is where we will put our textarea
const dataTd = parent.querySelector('td:last-child');
// create a new textarea element
const textarea = document.createElement('textarea');
// the textarea gets some class
textarea.classList.add('full');
// and a placeholder
textarea.placeholder = "Double click to translate";
// the arguments for this function are backwards to me, but I think it's self explanatory what's happening
dataTd.replaceChild(textarea, dataTd.firstChild);
// get that focus on the textarea.
dataTd.firstChild.focus();
});
function blurOrKeypress(e) {
// split up largely for readability
if (e.target.tagName !== 'TEXTAREA') return false;
if (e.type === 'keypress' && e.code != 'Enter' && !e.ctrlKey) return false;
// a parent, a row, and a newly minted text node walk into a bar...
const parent = e.target.parentElement;
const row = parent.parentElement;
const text = document.createTextNode(e.target.value || 'Double click to translate');
/* .isConnected refers to it's state in the DOM. this was some work to try and stop an error that was
ocurring due to this being simultaneously the 'blur' 'keypress' event handler. Alas, it didn't.
If the error is really an issue, then wrapping the parent.replaceChild in a try/catch block should solve it for you.*/
if (e.target.isConnected) {
// use the dataset key + the textarea's value to update the definitions.
definitions[row.dataset.key] = e.target.value;
// write those to the local storage
localStorage.setItem('definitions', JSON.stringify(definitions));
// Or, if you are using a database, you would use some variety of AJAX/XHR call here.
// get rid of our text element
parent.replaceChild(text, e.target);
// reset the editorshown value in case we need to update this again
row.dataset.editorShown = false;
}
}
// the one thing I miss about jquery event listeners: adding multiple types of event by putting spaces
tbody.addEventListener('keypress', blurOrKeypress);
tbody.addEventListener('focusout', blurOrKeypress);
// gets the key/value pairs and maps them
tbody.append(...Object.entries(definitions).map(([word, translation]) => {
// table row, key TD and value TD cells.
const tr = document.createElement('tr');
const keyTd = document.createElement('td');
const valueTd = document.createElement('td');
// editor is not shown by default
tr.dataset.editorShown = false;
// we use this in an upper function.
tr.dataset.key = word;
// add the bold class just for visual interest. you do not need to do this.
keyTd.classList.add('bold');
// set the inner text to our word
keyTd.innerText = word;
// if it's already set, great! use that. otherwise, 'double click to translate'
valueTd.innerText = translation || 'Double click to translate';
// add these two values to our newly minted tr tag.
tr.append(keyTd, valueTd);
// return the TR tag so that the above tbody.append gets an element to actually append
return tr;
}));
/* Styling here to make myself feel better*/
textarea.full {
height: 1.5rem;
width: 100%;
padding: 3px;
line-height: 1.5rem;
}
.bold {
font-weight: bold;
}
td.bold {
font-style: unset;
}
table {
border-collapse: collapse;
width: 100%;
}
td {
color: #111;
width: 50%;
border: 1px solid lightgray;
box-sizing: border-box;
padding: 5px 10px;
border-width: 1px 0;
font-style: italic;
}
th {
border: 2px solid lightgray;
border-width: 0 0 2px;
padding-bottom: 6px;
text-decoration: underline;
font-style: unset;
font-size: 1.15rem;
}
tbody tr:nth-child(odd) {
background-color: lightgray;
}
<table>
<thead>
<tr>
<th>Word/Phrase</th>
<th>Translation</th>
</tr>
</thead>
<tbody id="definitions">
<!-- HTML generated later -->
</tbody>
</table>
I'll work on an example using contentEditable when I come back to comment this when I wake up. Hope it helps in the meantime.
Try using getElementById.
const if_in_greek = document.getElementById('translate-if');
const than_in_greek = document.getElementById('translate-than');
const else_in_greek = document.getElementById('translate-else');
if_in_greek.ondblclick = function() {
if_in_greek.innerHTML = "Translation of IF goes here"
}
than_in_greek.ondblclick = function() {
than_in_greek.innerHTML = "Translation of THAN goes here"
}
else_in_greek.ondblclick = function() {
else_in_greek.innerHTML = "Translation of ELSE goes here"
}
table,
th,
td {
border: 1px solid black;
}
<section class="allEnglishSections">
<h2>Conditioning</h2>
<table>
<tr>
<th>English</th>
<th>Greek</th>
</tr>
<tr>
<td>if</td>
<td id="translate-if">Click to translate</td>
</tr>
<tr>
<td>than</td>
<td id="translate-than">Click to translate</td>
</tr>
<tr>
<td>else</td>
<td id="translate-else">Click to translate</td>
</tr>
</table>
</section>
( UPDATED: See last section. )
One way of doing this, is to create an object which maps english words to greek words, and then add an eventlistener that catches the double click event on the table element, checks if the 'click to translate' element has been clicked and do the translation:
const dict = {
if: "αν",
than: "από",
else: "αλλιώς"
}
document.querySelector("table").addEventListener("dblclick", function(e){
// Check if the .changeable element has triggered the click event
if ( e.target.classList.contains("changeable")){
// Get the text content from the sibling element which contains the english word
const word = e.target.previousElementSibling.textContent;
// Check if we have the word in our dictionary
if ( dict[word] ){
// Change the text content of the 'click to translate' element with the greek word
e.target.textContent = dict[word];
}
}
});
table {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
<section class="allEnglishSections">
<h2>Conditioning</h2>
<table>
<tr><th>English</th><th>Greek</th></tr>
<tr><td>if</td><td class="changeable">Click to translate</td></tr>
<tr><td>than</td><td class="changeable">Click to translate</td></tr>
<tr><td>else</td><td class="changeable">Click to translate</td></tr>
</table>
</section>
Updated
Notes: As #Jhecht correcly pointed out, the querySelectorAll returns a NodeList that needs to be iterated. The easiest way to do that, is through the forEach method available to the NodeList object. The code would be written like this:
document.querySelectorAll(".changeable").forEach(function(element){
element.addEventListener( "dblclick", function(){ /* CODE HERE */ } );
});
If you see trying to attach multiple event listeners to a web page, you should reconsider your choice and instead attach a single event listener on a parent object which will be receiving all the events of its inner children. I applied this pattern in my solution.
Since the question has been updated, and the intentions are more clear, I am adding another code that enables the user to double click on the Click to translate area and allow them to enter a custom value:
document.querySelector("table").addEventListener("dblclick", function(e){
if ( e.target.classList.contains("changeable")){
e.target.setAttribute("contenteditable", true);
if ( e.target.textContent === "Click to translate" ){
e.target.textContent = "";
e.target.focus();
}
}
});
<section class="allEnglishSections">
<h2>Conditioning</h2>
<table>
<tr><th>English</th><th>Greek</th></tr>
<tr><td>if</td><td class="changeable">Click to translate</td></tr>
<tr><td>than</td><td class="changeable">Click to translate</td></tr>
<tr><td>else</td><td class="changeable">Click to translate</td></tr>
</table>
</section>
var $TABLE = $('#table');
var $BTN = $('#export-btn');
var $EXPORT = $('#export');
$('.table-add').click(function () {
var $clone = $TABLE.find('tr.hide').clone(true).removeClass('hide table-line');
$TABLE.find('table').append($clone);
});
$('.table-remove').click(function () {
$(this).parents('tr').detach();
});
$('.table-up').click(function () {
var $row = $(this).parents('tr');
if ($row.index() === 1) return; // Don't go above the header
$row.prev().before($row.get(0));
});
$('.table-down').click(function () {
var $row = $(this).parents('tr');
$row.next().after($row.get(0));
});
// A few jQuery helpers for exporting only
jQuery.fn.pop = [].pop;
jQuery.fn.shift = [].shift;
$BTN.click(function () {
var $rows = $TABLE.find('tr:not(:hidden)');
var headers = [];
var data = [];
// Get the headers (add special header logic here)
$($rows.shift()).find('th:not(:empty)').each(function () {
headers.push($(this).text().toLowerCase());
});
// Turn all existing rows into a loopable array
$rows.each(function () {
var $td = $(this).find('td');
var h = {};
// Use the headers from earlier to name our hash keys
headers.forEach(function (header, i) {
h[header] = $td.eq(i).text();
});
data.push(h);
});
// Output the result
$EXPORT.text(JSON.stringify(data));
});
.table-editable {
position: relative;
.glyphicon {
font-size: 20px;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<div class="container">
<h1>HTML5 Editable Table</h1>
<p>Through the powers of <strong>contenteditable</strong> and some simple jQuery you can easily create a custom editable table. No need for a robust JavaScript library anymore these days.</p>
<ul>
<li>An editable table that exports a hash array. Dynamically compiles rows from headers</li>
<li>Simple / powerful features such as add row, remove row, move row up/down.</li>
</ul>
<div border="1" id="table" class="table-editable">
<span class="table-add glyphicon glyphicon-plus"></span>
<table style="border: 1px solid black;" class="table">
<tr>
<th>Name</th>
<th>Value</th>
<th></th>
<th></th>
</tr>
<tr>
<td contenteditable="true">Stir Fry</td>
<td contenteditable="true">stir-fry</td>
<td>
<span class="table-remove glyphicon glyphicon-remove"></span>
</td>
<td>
<span class="table-up glyphicon glyphicon-arrow-up"></span>
<span class="table-down glyphicon glyphicon-arrow-down"></span>
</td>
</tr>
<!-- This is our clonable table line -->
<tr class="hide">
<td contenteditable="true">Untitled</td>
<td contenteditable="true">undefined</td>
<td>
<span class="table-remove glyphicon glyphicon-remove"></span>
</td>
<td>
<span class="table-up glyphicon glyphicon-arrow-up"></span>
<span class="table-down glyphicon glyphicon-arrow-down"></span>
</td>
</tr>
</table>
</div>
<button id="export-btn" class="btn btn-primary">Export Data</button>
<p id="export"></p>
</div>
I am using the selection. I am selecting a value and getting the result in an input box, but the problem is, it is only working in the first row of my selection and not working when I am clicking second selection. Here is the code, Please share if you can solve this one or advice.
<script type="text/javascript">
function displayResult()
{
document.getElementById("mycall1").insertRow(-1).innerHTML = '<td><select id = "forcx" onchange="fillgap()"><option>Select</option> <option>Force</option><option>Angle</option><option>Area</option></select></td>';
document.getElementById("mycall2").insertRow(-1).innerHTML = '<td><input type="text" id="result1" size = "10" ></td>';
}
function fillgap(event){
var xnumb = 20;
var forcxlist = document.getElementById("forcx");
var forcxlistValue = forcxlist.options[forcxlist.selectedIndex].text;
if (forcxlistValue == "Force"){
document.getElementById("result1").value = xnumb;
}
}
</script>
Ok, so if i understand correctly
1) You want to add the: selection, results & + to the existing table
2) Add the options Force, Angle & Area to the select
3) If Force is selected, put the value '20' in the results td
4) When the + is clicked, a new row is added.
5 The newly added rows should behave exactly the same.
Given the above, I have done the following, I'm using jQuery as its simpler and I'm more familiar with it. Its easy.
The trick here is event delegation. at the time your page loads the new rows don't exist, that's why your JavaScript isn't working on them. you can read about it here: https://learn.jquery.com/events/event-delegation/
Here's the result:
$(document).ready(function() {
// add headers to table
$('table tr:first-child').append('<th>Result</th><th>Add</th>');
//add fields to table
$('table tr:not(:first-child)').append('<td><select class="selection"><option></option><option value="Force">Force</option><option value="Angle">Angle</option><option value="Area">Area</option></select></td><td class="result"></td><td><button type="button" class="displayResultBtn">+</button></td>');
// add new row when button is clicked
$('table').on('click','.displayResultBtn', function( event) {
var tRow = $(this).parent().parent().clone();
$(this).parents('table').append(tRow);
$('table tr:last-child td.result').empty();
});
// when the dropdown is changed, update the result to 20 if "Force" is selected.
$('table').on('change','.selection', function( event) {
var selection = $(this).val();
if (selection == "Force") {
$(this).parent().next().html('20');
// You can add more coditionals if you want to add didferent values for the other options.
} else {
$(this).parent().next().empty();
}
});
});
table,
td,
th {
border: 1px solid black;
white-space: nowrap;
}
table {
border-collapse: collapse;
width: 30%;
table-layout: auto;
}
td {
text-align: center;
vertical-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<table>
<tr>
<th>To</th>
<th>From</th>
<th>Detail</th>
<th>Selection</th>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>A+B</td>
</tr>
</table>
It's hard to answer with limited code provided, but I think your issue is that you are using id multiple times. Which is invalid. id should be unique and used once only.
I have put together some demo code here that will hopefully help you. It doesn't solve your exact problem(I dont have your html so i cant fully solve it). but hopefully this will give you an idea of how to handle accessing different rows, or specific unique ids.
I'm using jQuery here for simplicity, but the principle is the same:
Here's a fiddle if thats easier to play with: https://jsfiddle.net/BradChelly/4179e26q/
I hope this helps somewhat.
// highlight row by child selectors (:last-child)
$('#selectLastRowBtn').click(function(){
//clear any previous highlighting
$('#myTable tr:not(:first-child)').css('background-color','white');
// highlight the last row in the table.
$('#myTable tr:last-child').css('background-color','lightgrey');
});
// highlight row using a specific unique id
$('#selectRowByIdBtn').click(function(){
//get selected row id from dropdown
var rowId = $('#rowSelector option:selected').val();
//clear any previous highlighting
$('#myTable tr:not(:first-child)').css('background-color','white');
//highlight the row with the matching id from the selection dropdown
$('#myTable #row_'+rowId).css('background-color','lightgrey');
});
//
// ------Below is just stuff to make demo work, not relevant to the question
//
// Add row with unique id
$('#addNewRowBtn').click(function(){
var rowCount = $('#myTable tr').length;
$('#myTable').append('<tr id="row_'+rowCount+'"><td>23124</td><td>23124</td><td>23124</td><td>23124</td></tr>');
populateSelect(rowCount);
});
// populate select options
function populateSelect(rowCount){
$('#rowSelector').append('<option value="'+rowCount+'">'+rowCount+'</option>')
}
table {
width: 100%;
text-align: center;
}
table td {
border: 1px solid #333;
padding: 30px 0px;
}
table tr:first-child {
top: 0px;
background: #333;
}
table tr:first-child th {
color: #fff;
padding: 20px 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<table id="myTable">
<tr>
<th>Column One</th>
<th>Column Two</th>
<th>Column Three</th>
<th>Column Four</th>
</tr>
<tr id="row_1">
<td>23124</td>
<td>23124</td>
<td>23124</td>
<td>23124</td>
</tr>
</table>
<button id="addNewRowBtn">Add Row</button>
<h3>Using child selectors:</h3>
<button id="selectLastRowBtn">Highlight last row using child selector</button>
<h3>Highlight a row by id:</h3>
<select name="" id="rowSelector">
<option value="1">1</option>
</select>
<button id="selectRowByIdBtn">Highlight row by selected id</button>
I have a dynamic table that I made with javascript. Depending on different user events, some rows will be hidden, rearranged, ect. To be more specific, I'm using display:none; to do this. The issue is the rows always keep their original background color (imagine if all the rows were visible, then you could see the alternating colors). That would be fine if I had the entire table visible, but like I mentioned, sometimes certain rows will be hidden or appear at different positions. This often results in two or more rows of the same color being stacked on top of each other.
There is a similar post:
Alternate table row color even if row is removed
I tried as many of those solutions as I could. However my problem persists. Probably due to the following reasons:
I'm not removing the columns, I'm simply setting display:none;
I'm not working in a jquery environment, so I am limited to native javascript solutions
My code is:
tr:nth-child(even) {
background:gray;
}
tr:nth-child(odd) {
background:lightgray;
}
I have tried tr:nth-of-type(odd) and many similar variants. Is there anything else in CSS or native javascript I can try?
More on Visbility/Selection:
CSS:
tr:not(.selected) {
display: none;
}
JS:
my_circles.each(function(d,i) {
if (my_bool===true) {
d3.select(this).classed('selected',true);
tableRows.get(this).classed("selected", true);
}
});
I'm using d3.js, but I think I will omit the d3 tag, because this seems more of a css or js issue. This is a small snippet, mostly for context, but essentially we should be able to infer the visibility is toggled by a class assignment. If you are curious, it is whenever the user selects a circle on my adjacent scatter plot.
Unfortunately, there is no straight-forward CSS only solution for this problem. Primarily because the :not selector does not go together with nth-... selectors.
Your best bet would be to re-stripe your rows everytime via Javascript.
Stripe your rows as soon as your page is loaded. After that, whenever you change display on any row, you fire your stripe function again.
Here is a crude example:
var tab = document.getElementById("tab"),
btns = tab.getElementsByTagName("a"),
show = document.getElementById("show"),
rows
;
stripe(); // Stripe the rows in beginning
// The stripe function itself
function stripe() {
// select all rows which are not hidden
rows = tab.querySelectorAll('tr:not(.hidden)');
// add a class for every second such row
for(var x = 0; x < rows.length; x++) {
if (x % 2 == 0) { rows[x].classList.add('alt'); }
else { rows[x].classList.remove('alt'); }
}
}
// dummy buttons to hide each row in this demo
[].forEach.call(btns, function(elem) {
elem.addEventListener('click', hide);
});
// your actual code where you hide your rows
function hide(e) {
e.target.parentNode.parentNode.classList.add('hidden');
stripe(); // fire re-striping when hiding rows
}
// dummy button to show rows in this demo
show.addEventListener('click', function(e) {
rows = tab.querySelectorAll('tr.hidden');
[].forEach.call(rows, function(row) {
row.classList.remove('hidden');
});
stripe(); // fire re-striping when showing rows
});
table { width: 70%; border: 1px solid gray; border-collapse: collapse; }
td { border: 1px solid gray; padding: 4px; }
tr.hidden { display: none; }
#tab tr.alt { background-color: #ddd;}
<table id="tab"><tbody>
<tr><td>Row 1</td><td>Hide</td></tr>
<tr><td>Row 2</td><td>Hide</td></tr>
<tr><td>Row 3</td><td>Hide</td></tr>
<tr><td>Row 4</td><td>Hide</td></tr>
<tr><td>Row 5</td><td>Hide</td></tr>
</tbody></table><br />
<a id="show" href="#">Show All</a>
Accompanying fiddle: https://jsfiddle.net/abhitalks/dz5aq5fk/
.
It is not a CSS or native JS solution but here is a d3 based solution. You could change classes of the rows every time the rows in your table change.
d3.selectAll("tr.selected").classed("grey",function(d,i){return i%2 == 0});
It adds the grey class to every second row and removes it from all the rest. Then you can color rows using css.
tr.grey {
background:gray;
}
tr:not(.grey) {
background:lightgray;
}
Here is a jsbin that shows this strategy in action.
this is not a perfect solution, but you can use gradient background in table to get desired result.
below is sample using gradient background in table.
tr:not(.selected) {
display: none;
}
table {
background-color: gray;
background-image: linear-gradient(transparent 50%, lightgray 50%);
background-size: 100% 36px;
}
<table width="500" cellpadding="0" cellspacing="0">
<tr class="selected">
<td>A</td>
<td>B</td>
</tr>
<tr class="selected">
<td>C</td>
<td>D</td>
</tr>
<tr>
<td>E</td>
<td>F</td>
</tr>
<tr class="selected">
<td>G</td>
<td>H</td>
</tr>
<tr>
<td>I</td>
<td>J</td>
</tr>
<tr>
<td>E</td>
<td>F</td>
</tr>
<tr class="selected">
<td>G</td>
<td>H</td>
</tr>
<tr class="selected">
<td>G</td>
<td>H</td>
</tr>
<tr class="selected">
<td>G</td>
<td>H</td>
</tr>
<tr>
<td>I</td>
<td>J</td>
</tr>
</table>
As you correctly pointed out, the reason that the css alternating stripes dont work is that your rows are remaining in place, and just being hidden using display:none.
The trick is to "group" the visible and hidden rows together so that we dont end up with un-event striping. Given that the order of your rows is not important, what we can do is move the hidden rows to either the top (using .insertBefore) or bottom (using .appendChild) of their containing parent. Something similar to this:
my_circles.each(function(d,i) {
if (my_bool===true) {
d3.select(this).classed('selected',true);
var row = tableRows.get(this);
row.parentNode.appendChild(row);
row.classed("selected", true);
}
});
I am dynamically inserting a table row (or multiple rows) into a table upon an ajax call's return. I am looking to accomplish this by having an empty container type element inside of my html table that I can insert <tr> elements into. As I have seen from other posts, a div cannot hold a tr element, so my question is, is there a particular way that I can insert the html for row(s) into a table? It must be dynamic in nature, or in other words I need to be able to hold more than just one <tr>.
You can append to last row of table.
<table>
<tr><td>First Row</td></tr>
<tr><td>Middle Row</td></tr>
<tr><td>Last Row</td></tr>
</table>
<script>
$( "#tableid tr:last" ).append(
</script>
Assuming you aren't using jQuery, you can do something like this:
var myTable = document.getElementById('myTable').getElementsByTagName('tbody')[0];
var row = myTable.insertRow(myTable.rows.length);
You can then insert cells using insertCell on row.
Alternatively, if you have jQuery,
$("#myTable").append("<tr><td>Table Row with cell!</td></tr>");
I'm not sure why you wouldn't just use the <table> element directly, but you can use <tbody> elements as row containers within a table.
onload = function(){
document.getElementById("aButton").onclick = addRow.bind(null, "a");
document.getElementById("bButton").onclick = addRow.bind(null, "b");
}
function addRow(id) {
var r = document.getElementById(id).insertRow(-1);
var c = r.insertCell(-1);
c.innerHTML = "Row added at " + new Date().toLocaleTimeString();
}
body {
font-family: sans-serif;
font-size: 12px;
}
table {
border-collapse: collapse;
margin: 8px 0;
}
td {
border: 1px solid #ccc;
padding: 1px 2px;
}
<button id="aButton">Add row to 'A'</button>
<button id="bButton">Add row to 'B'</button>
<table>
<tbody><tr><td>Before A</td></tr></tbody>
<tbody id="a"></tbody>
<tbody>
<tr><td>After A</td></tr>
<tr><td>Before B</td></tr>
</tbody>
<tbody id="b"></tbody>
<tbody><tr><td>After B</td></tr></tbody>
</table>
I have a table where a row gets added every time I press a "Add" button. I have an "Edit" button which is placed in the first cell of the newly created row.
I want to highlight the row that is being edited. I know that I can get the current <tr> element like
var par = $(this).parent().parent();
But when I use,
par.css('border-color', 'red');
It does not change the color.
What mistake am I making and how should I highlight that particular row?
This is really about the styling of the <tr>. CSS doesn't like to style <tr>'s because they really only exist for semantics. In order to add a border to one, you need to make it display: block;.
Here is a jsFiddle and example code.
HTML
<table>
<tbody>
<tr><td>Some Content</td></tr>
<tr><td>Some Content</td></tr>
<tr>
<td>
Edit
</td>
</tr>
<tr><td>Some Content</td></tr>
<tr><td>Some Content</td></tr>
</tbody>
</table>
Javascript
$(".edit").click(function(e) {
$(this).closest('tr').toggleClass('editting');
e.preventDefault();
});
CSS
table tr {
display: block;
border: 1px solid rgba(0, 0, 0, 0);
}
.editting {
background: #FAA;
border: 1px solid red;
}
Please note how I used an rgba color to make the border opaque. There are other ways to do this, but if you leave the border off it causes the table to "jitter."
Assuming this refers to an element within the tr, then it will be better to use .closest() here
var par = $(this).closest('tr')