I am trying to make an interactive periodic table of elements. I need to change the background color of more <td> with the classname "nemetale" when a button is clicked. It's not working, I don't know what I am doing wrong.
There is the button
<button onclick="document.getElementsByClassName('.nemetale').style.backgroundColor = 'red';">Nemetale</button>
There is one of the <td>s.
<table class="tabel_periodic">
<!--Randul 1-->
<tr>
<td class="nemetale">
<strong>1</strong><br>
<acronym>H</acronym><br>
<em>Hidrogen</em><br>
<i>1,008</i>
</td>
...
Working fiddle.
getElementsByClassName() : Returns an array-like object of all child elements which have all of the given class names.
The function .getElementsByClassmame() doesn't exist you should use .getElementsByClassName().
Since the .getElementsByClassName() return a list of elements you should return the first element instead using [0] like :
document.getElementsByClassName('nemetale')[0].style.backgroundColor = 'red';
var trs = document.getElementsByClassName('nemetale');
document.getElementById('change_color').addEventListener('click', function() {
for (var i = 0; i < trs.length; i++) {
changeColor(trs[i]);
}
});
function changeColor(tr) {
tr.style.backgroundColor = 'red';
}
<button id="change_color">Nemetale</button>
<table class="tabel_periodic">
<tr>
<td class="nemetale">
<strong>1</strong><br>
<acronym>H</acronym><br>
<em>Hidrogen</em><br>
<i>1,008</i>
</td>
</tr>
<tr>
<td class="nemetale">
<strong>2</strong><br>
<acronym>H</acronym><br>
<em>Hidrogen</em><br>
<i>2,008</i>
</td>
</tr>
<tr>
<td class="nemetale">
<strong>3</strong><br>
<acronym>H</acronym><br>
<em>Hidrogen</em><br>
<i>3,008</i>
</td>
</tr>
</table>
Two things:
Firstly, there is a typo in the function you call. It should be getElementsByClassName().
Secondly, getElementsByClassName() returns a NodeList. This is “like” an Array, but it means you have to select each item from the NodeList.
If there is only one element, you can do
document.getElementsByClassName('nemetale')[0].style.backgroundColor = 'red';
If there is more than one element you will have to loop through the items. I recommend making it a function.
<button onclick="highlight">Nemetale</button>
function highlight() {
var items = document.getElementsByClassName('nemetale');
Array.from(items).forEach(function(item) {
item.style.backgroundColor = 'red';
});
}
If you are using ES6, you can make it a bit shorter as well:
function highlight() {
const items = document.getElementsByClassName('nemetale');
Array.from(items).forEach(item => item.style.backgroundColor = 'red');
}
You have a typo: getElementsByClassmame, this isn't a valid JS method.
Use .querySelector instead:
document.querySelector('.nemetale')
https://jsfiddle.net/d5dg0uw4/
Make it like below by adding function:
<button onclick="changeBackgroundColor()">Nemetale</button>
put this into
<script>
function changeBackgroundColor(){
document.getElementsByClassName('nemetale')[0].style.backgroundColor = 'red';
}
</script>
Related
I am trying to use a button inside a table division to set a variable as the same value as another division in the same row, but whenever I run my code (below), it returns the value of all the table divisions concatenated together. I am unsure why this was happening, so I replaced '.children()' with 'childnodes[0]' to try and get only the first name, but this just doesn't work and I don't why.
My html looks like this:
<table>
<tr>
<td>John</td>
<td>Doe</td>
<td><button>Get First Name</button></td>
</tr>
</table>
And my Javascript is this:
$(document).ready(function(){
$("button").click(function(){
var first = $(this).closest("tr").childNodes[0].text();
alert(first)
})
});
set a variable as the same value as another division in the same row
there are lots of possibilities for this, here are some (with the most useful first (opinion based))
$("button").click(function() {
var first = $(this).closest("tr").find("td:first").text();
var first = $(this).closest("tr").find("td").first().text();
var first = $(this).closest("tr").find("td").eq(0).text();
var first = $(this).closest("tr").children().first().text();
var first = $(this).closest("tr").children().eq(0).text();
var first = $(this).closest("td").siblings().first().text();
});
it returns the value of all the table cells concatenated together
https://api.jquery.com/text
Get the combined text contents of each element in the set of matched elements, including their descendants, or set the text contents of the matched elements.
because you're passing the "tr" to text() it gets the text of all the cells (tds) and their content etc and combines them as one, so you need to limit to the first as you've attempted.
however .childNodes[0] can only be applied to a DOM element/node, while $(this).closest("tr") gives you a jquery object/collection, which doesn't have .childNodes property.
So the jquery equivalent would be to use .children().eq(0).
You could use class identifiers to get information you need as well.
<table>
<tr>
<td><span class="first-name">John</span></td>
<td><span class="last-name">Doe</span></td>
<td>
<button class="btn-get-data" data-class="first-name">Get First Name</button>
<button class="btn-get-data" data-class="last-name">Get Last Name</button>
</td>
</tr>
</table>
$(document).ready(function() {
$(".btn-get-data").click(function() {
$btn = $(this);
$tr = $btn.closest('tr');
var first = $tr.find('.' + $btn.attr('data-class')).html();
alert(first);
})
});
If you make the button click generic like so, you can add additional buttons on the page and use that to get the class within that row.
Here is a working fiddle example: https://jsfiddle.net/b1r0nucq/
you could find the :first child and get his html(), as below:
$(document).ready(function() {
$("button").click(function() {
var first = $(this).closest("tr").children(":first").html();
alert(first)
})
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<td>John</td>
<td>Doe</td>
<td><button>Get First Name</button></td>
</tr>
</table>
I have a table that's created with asp net using a foreach to iterate through the instances of the viewModel.
I need to change the bakcground color of those but they all have the same id
HTML
#foreach (var item in Model)
{
<tr id="test">
<td>
<p class="small">#Html.DisplayFor(modelItem => item.DT_CADASTRO_FORMATADO)</p>
</td>
<td>
#Html.DisplayFor(modelItem => item.DSC_NATUREZA_INICIAL)
</td>
</tr>
}
JavaScript
$("document")
.ready(function ToPink() {
for (var i = 0; i < 26; i++) {
let tab = document.getElementById("test");
if (tab.cells[1].innerText == 'foo') {
alert(tab.cells[1].innerText);
}
}
});
Well, the IDs should be unique, but what you are looking for is a CSS class. Add a class to the tds and then use document.getElementsByClassName to pull all the elements with that class name.
ID should be unique because getElementById function searches for only one element that is first present with given ID:
alert(document.getElementById("nounique").innerHTML);
<div id="nounique">1</div>
<div id="nounique">2</div>
Give each table a class and in the javascript you query all TD elements
<table class="test">
....
</table>
<script>
var TDs = document.querySelectorAll(".test td");
for (var i=0; i < TDs.length; i++) {
// use TDs[i] here to style your html
}
</script>
Ofcourse you may use jQuery
$(document).ready(function() {
$(".test td").each(function(index) {
// use $(this) here to style your html
});
});
I want to get value like in subject, from cell but that cell have element <a>1</a> and in this element is the value.
I tried something like this:
function filter(gvId) {
var table = document.getElementById(gvId);
for (var c = 1; c < table.rows[2].cells.length; c++) {
for (var r = headerNumber; r < table.rows.length; r++) {
var value = table.rows[r].cells[c].getElementsByClassName("a").innerHTML;
console.log(value); //and it should show me :
//1
//2
//3
//4
}
}
}
<table>
<tbody>
<tr>
<td><a>1</a>
</td>
<td><a>2</a>
</td>
</tr>
<tr>
<td><a>3</a>
</td>
<td><a>4</a>
</td>
</tr>
</tbody>
</table>
Everything works greate without <a> tag inside cell. But now I don't know how to get this value.
In your case, the problem is in a row:
var value = table.rows[r].cells[c].getElementsByClassName("a").innerHTML;
Because you're trying to match an element by class, but not by element tag. Link tag <a> has no className a. Your current code will work fine for: <a class="a">1</a> or <div class="a"></div>.
May be you should try something like querySelector instead? Like:
var value = table.rows[r].cells[c].querySelector('a').innerHTML;
Please, also check the MDN docs about getElementsByClassName and querySelector
UPD: All the code could be simplified:
var contentLinks = table.querySelectorAll('td a');
contentLinks.forEach(function(item) {
var value = item.innerHTML;
console.log(value);
});
Get the text content of an element with .textContent instead of .innerHTML
var value = table.rows[r].cells[c].textContent;
Documentation here and here
Title might be a bit confusing, but this is the best I could come up with.
I need to find all tr elements which contains td elements matching the filter criteria provided.
Here is my sample,
<tr class="row" id="1">
<td class="philips">PHILIPS</td>
<td class="h4">H4</td>
<td class="lamp">Lamp<td>
</tr>
<tr class="row" id="2">
<td class="philips">PHILIPS</td>
<td class="h5">H5</td>
<td class="bulb">Bulb<td>
</tr>
<tr class="row" id="3">
<td class="neglin">NEGLIN</td>
<td class="w5w">W5W</td>
<td class="tube">Tube<td>
</tr>
<tr class="row" id="4">
<td class="philips">PHILIPS</td>
<td class="h4">H4</td>
<td class="bulb">Bulb<td>
</tr>
<tr class="row" id="5">
<td class="osram">OSRAM</td>
<td class="hb3">HB3</td>
<td class="tube">Tube<td>
</tr>
<tr class="row" id="6">
<td class="neglin">NEGLIN</td>
<td class="w5w">W5W</td>
<td class="lamp">Lamp<td>
</tr>
If I pass filter[0] as 'phillips', the result return tr with id
1
2 and
4
Then if I pass second filter; filter[1] as 'h4', the result should be filtered down to
1 and
4
I have tried this question.
Which has this answer.
$('tr')
.has('td:nth-child(1):contains("Audi")')
.has('td:nth-child(2):contains("red")')
.doSomeThing();
But, I want my filters to be applied dynamically. How would I be able to insert a 3rd has function?
I don't want to go the if-else or switch-case way, if this is possible with out them.
You can try this.
<script type="text/javascript">
$(document).ready(function () {
var result = filter([".philips", ".h4"]);
alert(result);
var result_2 = filter([".philips"]);
alert(result_2);
});
function filter(params) {
var select = "tr";
for (var i = 0; i < params.length; i++) {
select += ":has(" + params[i] + ")";
}
return $(select).map(
function () {
return $(this).attr('id');
}
).get();
}
</script>
if you have an array of filters needed, iterate that array and pass the filter string to the has?
var filters = ['PHILIPS', 'H4', 'Bulb']
var result = $('tr');
for(var i = 0; i < filters.length; i++){
var nchild = i+1;
result = result.has('td:nth-child('+nchild+'):contains("+'filters[i]'+")');
}
edit to your needs of course, but this way you can take user input, compile that into the needed array and then iterate whatever is in the array to filter down results.
You should wrap the $.has() into a separate function (I've just used jquery's easy extensions supports) which will expose the usage as a composite function chain via javascript's syntax...
$( document ).ready(function() {
$('tr')
.nthFilter('td:nth-child(1):contains("PHILIPS")')
.nthFilter('td:nth-child(2):contains("H4")')
.nthFilter('td:nth-child(3):contains("Bulb")')
.css("background-color", "red");
});
jQuery.fn.extend({
nthFilter: function(filter) {
return $(this).has(filter);
}
});
I've put together a small jsfiddle for you to fiddle with :)
You can supply your filter as a string:
var filter = ".philips, .h4";
$("tr").has("td").has(filter).map(function() { return this.id; });
// returns ["1", "2", "4"]
and if you want the elements then obviously leave the map off:
$("tr").has("td").has(filter);
// returns array of <tr>
Edit: Just noticed you want recursive filtering so change the filter to use sibling selector ~.
var filter = ".philips ~ .h4";
// returns ["1", "4"]
So if you want a third level then just:
var filter = ".philips ~ .h4 ~ .bulb";
// returns ["4"]
How do I remove the parent element and all the respective nodes using plain JavaScript? I'm not using jQuery or any other library.
In other words, I have an element and when user clicks on it, I want to remove the parent of the parent element (as well as the respective children nodes).
<table id='table'>
<tr id='id'>
<td>
Mohit
</td>
<td>
23
</td>
<td >
<span onClick="edit(this)">Edit</span>/<span onClick="delete_row(this)">Delete</span>
</td>
<td style="display:none;">
<span onClick="save(this)">Save</span>
</td>
</tr>
</table>
Now,
function delete_row(e)
{
e.parentNode.parentNode.removeChild(e.parentNode);
}
Will remove only last <td>.
How do I remove the <tr> directly>?
e.parentNode.parentNode.getAttribute('id')
returns the id of the row...
Is there any function like remove() or delete() ?
Change your function like this:
function delete_row(e)
{
e.parentNode.parentNode.parentNode.removeChild(e.parentNode.parentNode);
}
You can now use node.remove() to remove the whole element
so in your case you'd do
function delete_row(e) {
e.parentElement.remove();
}
You can read more on it here
https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove
node.parentNode.parentNode.removeChild(node.parentNode)
Edit: You need to to delete parent of parent, so add one more .parentNode
node.parentNode.parentNode.parentNode.removeChild(node.parentNode.parentNode)
Or for those who like a one-liner
<button onClick="this.parentNode.parentNode.removeChild(this.parentNode);">Delete me</button>
Change this:
onClick="delete_row(this)"
To this:
onClick="removeParents(this, document.getElementById('id'))"
function removeParents(e, root) {
root = root ? root : document.body;
var p = e.parentNode;
while(root != p){
e = p;
p = e.parentNode;
}
root.removeChild(e);
}
http://jsfiddle.net/emg0xcre/
You can specify it even more. Instead of parentElement.parentElement you can do something like this:
static delete_row(element) {
element.closest("tr").remove();
}
The other preferred way of handling such scenario would be event propagation instead of adding onclick to html element:
document.querySelector("#id").addEventListener("click", (e) => {
UI.handleEvents(e.target);
});
static handleEvents(el){
if (el.classList.contains("delete")) {
el.closest("tr").remove();
}
if (el.classList.contains("edit")) {
// do something else
}
if (el.classList.contains("save")){
// save records
}
}
<tr id='id'>
<td>Mohit</td>
<td>23</td>
<td >
<span class="edit">Edit</span> |
<span class="delete">Delete</span>
</td>
<td style="display:none;"><span class="save">Save</span></td>
</tr>
Simple function to do this with ES6:
const removeImgWrap = () => {
const wrappedImgs = [...document.querySelectorAll('p img')];
wrappedImgs.forEach(w => w.parentElement.style.marginBottom = 0);
};
I know it's a little too late, but someone else might find it useful.
e.target.parentElement.parentElement.parentElement.remove()
<div>
<span>1<button onclick="removeParents(this);">X</button></span>
<span>2<button onclick="removeParents(this);">X</button></span>
<span>3<button onclick="removeParents(this);">X</button></span>
<span>4<button onclick="removeParents(this);">X</button></span>
</div>
<script>
function removeParents(e) {
var root = e.parentNode;
root.parentNode.removeChild(root);
console.log(root);
}
</script>
working sample
If you want to delete whatever is inside the <tr> tags, by clicking on the "Delete", give that span a class name (whatever you want).
Then, in JS code: you basically select the element people will click with the document.querySelector(), add an Event Listener to it & on clicking on that span with that .whatever class, the element with the ID name "id" will be removed.
document.querySelector('.wtvr').addEventListener('click', function () {
document.getElementById('id').remove();
});
<table id="table">
<tr id="id">
<td>Mohit</td>
<td>23</td>
<td><span>Edit</span>/<span class="wtvr">Delete</span></td>
<td style="display: none">
<span>Save</span>
</td>
</tr>
</table>
I took the onclick away because you can delete a DOM element just using CSS class and a bit of JS.