I'm trying to get two buttons to switch between 2 tables with javascript, but whenever i test, both of the tables appear instead of just one
var table1 = document.getElementById("table1");
var table2 = document.getElementById("table2");
var btnTab1 = document.getElementById("showTable1");
var btnTab2 = document.getElementById("showTable2");
btnTab1.onclick = function() {
table1.style.display = "table";
table2.style.display = "none";
}
btnTab2.onclick = function() {
table1.style.display = "none";
table2.style.display = "table";
}
<table id=table1>
<table id=table2>
<input type="button" id="showTable1" value="Table 1">
<input type="button" id="showTable2" value="Table 2">
I expect 1 table to be showing at a time and the button to switch between them, but instead they both show at the same time and the buttons dont do anything
var table1 = document.getElementById("table1");
var table2 = document.getElementById("table2");
var btnTab1 = document.getElementById("showTable1");
var btnTab2 = document.getElementById("showTable2");
btnTab1.onclick = function() {
table1.style.display = "table";
table2.style.display = "none";
}
btnTab2.onclick = function() {
table1.style.display = "none";
table2.style.display = "table";
}
#table2 {
display: none;
}
<table id="table1">
<tr>
<td>Table1</td>
</tr>
</table>
<table id="table2">
<tr>
<td>Table2</td>
</tr>
</table>
<input type="button" id="showTable1" value="Table 1">
<input type="button" id="showTable2" value="Table 2">
Your code is right but you just forgot to initialize the display on your tables and to close the table tags :
(I added some content so we see which table is visible)
var table1 = document.getElementById("table1");
var table2 = document.getElementById("table2");
var btnTab1 = document.getElementById("showTable1");
var btnTab2 = document.getElementById("showTable2");
btnTab1.onclick = function() {
table1.style.display = "table";
table2.style.display = "none";
}
btnTab2.onclick = function() {
table1.style.display = "none";
table2.style.display = "table";
}
<table id=table1 style="display: table">
<thead>
<tr>
<th colspan="2">The table header 1</th>
</tr>
</thead>
</table>
<table id=table2 style="display: none">
<thead>
<tr>
<th colspan="2">The table header 2</th>
</tr>
</thead>
</table>
<input type="button" id="showTable1" value="Table 1">
<input type="button" id="showTable2" value="Table 2">
I'm replacing your tables with divs, because it's easier to show the thought behind the code with less clutter.
You can add listeners directly onto the buttons, and by doing that, it's easier to send in parameters. I made something a little bit more dynamic, where it's possible to add any number of tables with ease without having to change the code. All you need to do is change the parameter in showTable('table2') to showTable('table3') in the button.
This solutions wont demand as many variables, and it's not dependent on whether the page has loaded or not. Like #brianfit said, you're probably having your javascript code in the head element which means that the document doesn't exist when the code runs, and you can't therefor find any elements on the page.
I also think it's better to use classes to style elements, rather changing the style in code. The semantics looks better, and you get IMHO a better understanding of why some tables are hidden.
function showTable(tableIdToShow) {
hideAllTables();
let tableElement = document.getElementById(tableIdToShow);
tableElement.classList.add('show');
}
function hideAllTables() {
let allTableElements = document.querySelectorAll('.table');
for (tableElement of allTableElements) {
tableElement.classList.remove('show')
}
}
.table {
display: none;
}
.table.show {
display: block;
}
<div id="table1" class="show table">TABLE 1</div>
<div id="table2" class="table">TABLE 2</div>
<input type="button" onclick="showTable('table1')" value="Table 1">
<input type="button" onclick="showTable('table2')" value="Table 2">
If your code block is in the header, try moving it down to just before the closing body tag. I just ran it both ways, and it doesn't work in the header, does work in body.
The reason: the script is loaded in the header before the html, so the getelementbyid call returns null. By placing the script after the html, the div populates the id and the script loads it properly.
If you load your file in Chrome and turn on the Javascript console, you would have seen an error message similar to the following:
(index):12 Uncaught TypeError: Cannot set property 'onclick' of null
at (index):12
Your script is correct and is working. The problem was with the <table>. it was empty and not closed. So you were not able to notice the change in table display. try the below sample.
var table1 = document.getElementById("table1");
var table2 = document.getElementById("table2");
var btnTab1 = document.getElementById("showTable1");
var btnTab2 = document.getElementById("showTable2");
btnTab1.onclick = function () {
table1.style.display = "block";
table2.style.display = "none";
}
btnTab2.onclick = function () {
table1.style.display = "none";
table2.style.display = "block";
}
<table id=table1>
<tr>
<td>table 01</td>
</tr>
</table>
<table id=table2>
<tr>
<td>table 02</td>
</tr>
</table>
<input type="button" id="showTable1" value="Table 1">
<input type="button" id="showTable2" value="Table 2">
Related
I want to manipulate (add/delete rows) for two tables in html using JavaScript. With one it works, but if I add the second one I get this error:
Uncaught TypeError: Cannot set property 'innerHTML' of null
More precisely: I want to have two tables each with different content based on which button is clicked.
With one table it worked. The first function deleted table content -> added new content. Second function the same, deleted content from first table -> added its new content.
But I want to do this with two tables. Please let me know how it should be done.
function First(tableID, tableID2) {
let table = document.getElementById(tableID)
table.innerHTML = ""; // here is the mentioned error.
// I would like to have something like..
// let table2 = document.getElementById(tableID2)
// table2.innerHTML = "";
}
<p>Click the button to add a new row at the first position of the table and then add cells and content</p>
<table id="myTable">
<TR>
</TR>
</table>
<table id="myTable2">
<TR>
</TR>
</table>
<br>
<button type="button" id="first" onclick="First(myTable, myTable2)">First</button>
<button type="button" id="second" onclick="Second(myTable, myTable2)">Second</button>
If you don't wrap myTable and myTable2 in quotations, JavaScript assumes it is an object. Since you didn't define myTable nor myTable2, they are null. You can't modify the innerHTML of null, and thus you get the error "Cannot set property 'innerHTML' of null".
In the example below, the names are wrapped in quotations which makes it a String:
function First(tableID, tableID2) {
let table = document.getElementById(tableID)
table.innerHTML = "<tr>first</tr>"; // here is the mentioned error.
let table2 = document.getElementById(tableID2)
table2.innerHTML = "<tr>first again</tr>";
}
function Second(tableID, tableID2) {
let table = document.getElementById(tableID)
table.innerHTML = "<tr>second</tr>"; // here is the mentioned error.
let table2 = document.getElementById(tableID2)
table2.innerHTML = "<tr>second again</tr>";
}
<p>Click the button to add a new row at the first position of the table and then add cells and content</p>
<table id="myTable">
<TR>
</TR>
</table>
<table id="myTable2">
<TR>
</TR>
</table>
<br>
<button type="button" id="first" onclick="First('myTable', 'myTable2')">First</button>
<button type="button" id="second" onclick="Second('myTable', 'myTable2')">Second</button>
Alternatively, you could define the two variables before they are referenced:
function First(tableID, tableID2) {
let table = document.getElementById(tableID)
table.innerHTML = "<tr>first</tr>"; // here is the mentioned error.
let table2 = document.getElementById(tableID2)
table2.innerHTML = "<tr>first again</tr>";
}
function Second(tableID, tableID2) {
let table = document.getElementById(tableID)
table.innerHTML = "<tr>second</tr>"; // here is the mentioned error.
let table2 = document.getElementById(tableID2)
table2.innerHTML = "<tr>second again</tr>";
}
<p>Click the button to add a new row at the first position of the table and then add cells and content</p>
<table id="myTable">
<TR>
</TR>
</table>
<table id="myTable2">
<TR>
</TR>
</table>
<br>
<script>
var myTable = 'myTable';
var myTable2 = 'myTable2';
</script>
<button type="button" id="first" onclick="First(myTable, myTable2)">First</button>
<button type="button" id="second" onclick="Second(myTable, myTable2)">Second</button>
just add some quotation mark on your args when calling your function. Otherwise, javascript think "myTable" is a variable, which doesn't exists.
<button type="button" id="first" onclick="First('myTable', 'myTable2')">First</button>
Were you trying to use just one function to edit both tables? Here's a version of that. Just pass in the ID of the table with a string.
function eTable(tableID) {
let table = document.getElementById(tableID)
let row = table.insertRow(0);
let cell = row.insertCell(0);
cell.innerHTML = "New cell for " + tableID;
}
<p>Click the button to add a new row at the first position of the table and then add cells and content</p>
Table 1:
<table id="myTable">
<TR>
</TR>
</table>
Table 2:
<table id="myTable2">
<TR>
</TR>
</table>
<br>
<button type="button" id="first" onclick="eTable('myTable')">First</button>
<button type="button" id="second" onclick="eTable('myTable2')">Second</button>
I am using PHP and MySQL to build an HTML table. I am trying to use JavaScript to filter/search the table and only display the rows with the results I need. I want the JavaScript input to search multiple <td>s of the table. I was able to get this to work, but it is not going to be an elegant solution to put in place with larger tables.
I am sure there is a better way to choose what is being searched, but have not been able to find anything. Does anybody know a way for me to make this code more flexible for varying column width tables?
function myFunction() {
var input, filter, table, tr, td, i;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
td1 = tr[i].getElementsByTagName("td")[1];
if (td+td1) {
if ((td.innerHTML.toUpperCase().indexOf(filter)+td1.innerHTML.toUpperCase().indexOf(filter)) > -2) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search" title="Type in anything">
<table id="myTable">
<tr class="header">
<th style="width:60%;">Name</th>
<th style="width:40%;">Country</th>
</tr>
<tr>
<td>North/South</td>
<td>UK</td>
</tr>
<tr>
<td>Paris specialites</td>
<td>France</td>
</tr>
</table>
There's a lot you can improve. Start by remembering to explicitly declare your variables, otherwise they become global.
This solution doesn't rely on any specific number of columns. It will work no matter how many there are.
See comments inline for more:
// Get DOM references just once:
var input = document.getElementById("myInput");
var table = document.getElementById("myTable");
// Do event binding in JavaScript, not HTML
input.addEventListener("keyup", filter);
input.addEventListener("search", filter);
// Get all rows, except the header and convert to array so .forEach() can be used to loop
var rows = Array.prototype.slice.call(table.querySelectorAll("tr:not(.header)"));
function filter() {
// Always trim user input
var filter = input.value.trim().toUpperCase();
// Loop the rows
rows.forEach(function(row) {
// You really don't need to know if the search criteria
// is in the first or second cell. You only need to know
// if it is in the row.
var data = "";
// Loop over all the cells in the current row and concatenate their text
Array.prototype.slice.call(row.getElementsByTagName("td")).forEach(function(r){
// Don't use .innerHTML unless there is HTML. Use textContent when there isn't.
data += r.textContent;
});
// Check the string for a match and show/hide row as needed
// Don't set individual styles. Add/remove classes instead
if(data.toUpperCase().indexOf(filter) > -1){
// show row
row.classList.remove("hidden");
} else {
// hide row
row.classList.add("hidden");
}
});
}
input[type=search]{
border-radius:10px;
outline:0;
padding:3px;
}
input[type=search]:focus{
box-shadow:0 0 4px blue;
}
.hidden { display:none; }
.leftHeader { width:60%; }
.rightHeader { width:40%; }
<!-- Use the actual "search" input type and don't do inline CSS or JavaScript -->
<input type="search" id="myInput" placeholder="Search" title="Type in anything">
<table id="myTable">
<tr class="header">
<th class="leftHeader">Name</th>
<th class="rightHeader">Country</th>
</tr>
<tr>
<td>North/South</td>
<td>UK</td>
</tr>
<tr>
<td>Paris specialites</td>
<td>France</td>
</tr>
</table>
All what you have to do is to get the td content and then match it with the search input.
function search(value) {
$('table tr').each(function () {
var content = $(this).find('td').text();
if (content.toUpperCase().includes(value.trim().toUpperCase())) {
$(this).show();
} else {
$(this).hide();
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<body>
<input type="search" placeholder="Search..." id="search_account" onkeyup="search(this.value)">
<table>
<tr>
<td>Cell1</td>
<td>Cell2</td>
<td>Cell3</td>
</tr>
<tr>
<td>Cell4</td>
<td>Cell5</td>
<td>Cell6</td>
</tr>
</table>
</body>
</html>
I have a button:
<button id="external-list-row">Test</button>
in which I would like to change with a row from an external table on click. The external table is structured like this;
<table id="table_id">
<thead>
<tr>
<th>X</th>
<th>Y</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>Row 1</p>
</td>
</tr>
<tr>
<td>
<p>Row 2</p>
</td>
</tr>
<tr>
<td>
<p>Row 3</p>
</td>
</tr>
</tbody>
</table>
So my question is this; how can I replace "Test" in the button with the content of Row 1 with javascript?
As for the javascript, I'm not sure how I can get the content from row 1, and replace the button with it.
<script>
var rows = document.getElementById('table_id').getElementsByTagName("tr");
for (var i=0; i<rows.length; i++) {
$('#external-list-row').onclick = function() {
}};
</script>
Post comments:
I can access table data from other tables within the same html file, but I still don't know how to access data from tables in other html files. For example, if I try to access a videos liquid file from another liquid file, like photos, nothing happens when I press the button.
Fiddle of current code. It can replace the content of a list with the content of another, but the lists need to be on the same html file.
https://jsfiddle.net/hgnymydL/
Well, the first thing you should understand, is that a table element has a rows property, so getting the first row is trivial.
var table = document.getElementById("table_id");
var firstRow = table.rows[0];
From there, you can use textContent to get the text content of the row. I believe that's what you were looking for.
You can also select the first row of a table with a CSS selector like so:
var firstRow = document.querySelector("#table_id tbody tr");
$('#external-list-row').on('click', function() {
$(this).text($('#table_id tbody tr:first').text());
});
If you want to replace the button text with contents of the First Row ONLY then:
$('#external-list-row').html($('tr:first-child').html);
Of course you could wrap this in any event, so for example, on clicking the button:
$('#external-list-row').on('click', function() {
$(this).html($('tr:first-child').text());
});
BUT, based on the code you have given, I'm assuming you want to change the text after each click in which case you could do this:
var clickNumber = -1;
$('#external-list-row').on('click', function(event) {
clickNumber = clickNumber + 1;
//console.log('\n\nclickNUmber' + clickNumber);
$('tbody tr').each(function(index, el) {
//console.log('index: ' + index);
var block = $(el).find('td p');
if(index == clickNumber) {
//console.log('entered if')
//console.log(block.text());
//console.log('----clickNUmber' + clickNumber);
//console.log('index: ' + index);
//console.log(el);
$('#external-list-row').html(block.text());
}
});
});
jsFiddle: https://jsfiddle.net/zmb2b37t/
Hope that helps!
If you are wanting to replace the visible text "Test" in the button with the content of the cell clicked:
var tbl = document.getElementById('table_id');
var btn = document.getElementById('external-list-row');
tbl.onclick = function(ev){
var trgt = ev.target;
if(trgt.tagName === 'P' ||trgt.tagName === 'TD'){
btn.textContent = trgt.textContent;
}
};
Only one event handler is attached in this scenario.
Via event delegation we determine if it was a TD or P element that was clicked. If the rows are modified the function will still work.
Here is jquery code of do this
$('#table_id tr td').on('click', function(){
$('#external-list-row').html($(this).html());
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="external-list-row">Test</button>
<table id="table_id">
<thead>
<tr>
<th>X</th>
<th>Y</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>Row 1</p>
</td>
</tr>
<tr>
<td>
<p>Row 2</p>
</td>
</tr>
<tr>
<td>
<p>Row 3</p>
</td>
</tr>
</tbody>
</table>
I have a table that I am trying to display and activate form information in on a button click. The table is set to "display: none" and the button is connected to the javascript. The javascript works but only after the button has been clicked a second time. I would like for it to work the first time it is clicked.
Button & Table HTML:
<button data-bind="click: addPatient" style="margin-top: 20px; margin-bottom: 10px;">Add Patient</button>
<table id="newPatientForm">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th></th>
</tr>
<tbody data-bind="foreach:Patients">
<tr>
<td class="form-group"><input data-bind="value: FirstName, event: {change: flagPatientAsEdited}, hasfocus: true" /></td>
<td class="form-group"><input data-bind="value: LastName" /></td>
<td class="form-group"><button data-bind="click: $parent.removePatient">Delete</button></td>
</tr>
</tbody>
</table>
This is the table CSS:
#newPatientForm {
display: none;
}
This is the javascript that the button calls.
self.addPatient = function () {
var divElement = document.getElementById('newPatientForm');
var patient = new PatientViewModel({ SiteId: 0, FirstName: "", LastName: "", ObjectState: ObjectState.Added });
if (divElement.style.display == 'none') {
divElement.style.display = 'block';
self.Patients.push(patient);
}
else {
divElement.style.display = 'none';
self.Patients.pop(patient);
}
},
You need to check the computed style when it is set in a stylesheet
function isHidden(elem) {
var style = window.getComputedStyle(elem);
return style.display === "none";
}
Change
if (divElement.style.display == 'none') {
to
if (isHidden(divElement)) {
which uses the above method.
It would probably bet better to just have a class that is hidden or not and toggle the class.
And finally, I do not think self.Patients.pop(patient); is doing what you think it is doing. the pop method has no arguments. It does not find and remove elements.
I have a jQuery function I wrote which will slideToggle an additional table row. There is a cell at the end of the clickable row that contains a button, however as the click of a container div triggers the function, clicking anywhere in the row will cause the new row to expand.
I need the function to only be triggered when the button is clicked as there is scope to add checkboxes, links etc to other parts of the table.
Code:
var toggleSpeed = 600;
var expandText = "more";
var collapseText = "less";
$(".extrainfo_container").click(function() {
$(this).find('.extrainfo').slideToggle(toggleSpeed);
if ($(this).find('.moreless').text() == collapseText) {
$(this).find('.moreless').text(expandText)
}
else {
$(this).find('.moreless').text(collapseText);
}
});
<table>
<tr>
<td>Header 1</td>
<td>Header 2</td>
<td>Header 3</td>
</tr>
</table>
<div class="extrainfo_container">
<table>
<tr>
<td>Col 1</td>
<td>Col 2</td>
<td><div class="moreless">more</div></td>
</tr>
<tr>
<td colspan="3">
<div class="extrainfo">
Extra information.<p />
Extra information.<p />
</div>
</td>
</tr>
</table>
</div>
Working example: http://jsfiddle.net/E22XR/69/
I have searched the forums, and although I did find similar questions and answers, none of them worked for me. I figure there must be something different I am doing, and/or there is a better way to achive the same result - I am quite new to writing my own functions.
If there is a better way, a requirement is that I do not use IDs as there could be any number of rows created dynamically.
You could do this I guess.
var toggleSpeed = 600;
var expandText = "more";
var collapseText = "less";
$(".moreless").click(function() {
$(".extrainfo_container").find('.extrainfo').slideToggle(toggleSpeed);
if ($(".extrainfo_container").find('.moreless').text() == collapseText) {
$(".extrainfo_container").find('.moreless').text(expandText)
}
else {
$(".extrainfo_container").find('.moreless').text(collapseText);
}
});
Edit : Hack for multiples rows
var toggleSpeed = 600;
var expandText = "more";
var collapseText = "less";
$(".moreless").click(function () {
var detailsRow = $(this).parent().parent().next();
detailsRow.find('.extrainfo').slideToggle(toggleSpeed);
if ($(this).text() == collapseText)
$(this).text(expandText);
else
$(this).text(collapseText);
});