jQuery parent() function returns empty - javascript

I have the following html (simplified to basic setup):
<div class="findme">
<table>
<tr>
<td>
<img id="image" src="image.png" onclick="findTheDiv(event)" />
</td>
</tr>
</table>
</div>
When I click on the image, the findTheDiv(event) function runs, which looks like this:
function findTheDiv(event) {
var elem = $(event.toElement);
var found = false;
// stop the loop if the top-level element is reached (html)
while (!$(elem).is("html")) {
if ($(elem).is("div.findme")) {
found = true;
break;
}
elem = $(elem).parent();
console.log(elem);
}
}
This runs, and for each iteration of the while loop, I log the new elem, which is the previous element's parent, to the console. This is the result I get:
[<img id="image" src="image.png" onclick="findTheDiv(event)">]
[<td>]
[<tr>]
[<table>]
[]
When the table is reached, it apparently has no parent, even though it clearly does, which is the div. To further test this, I used the console to execute this:
$("table").parent();
And it returned a blank array
[]
Why is jQuery saying the table does not have a parent, since all elements except for the <html> have parents?

I changed your code a little and it works fine. Instead of using an event object as an argument, I just pass this to reference the object which fires the event directly. This serves the same purpose.
function findTheDiv(elem) {
//var elem = $(event.toElement);
var found = false;
// stop the loop if the top-level element is reached (html)
while (!$(elem).is("html")) {
if ($(elem).is("div.findme")) {
found = true;
break;
}
elem = $(elem).parent();
console.log(elem);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="findme">
<table>
<tr>
<td>
<img id="image" src="image.png" onclick="findTheDiv(this)" />
</td>
</tr>
</table>
</div>
Run the snippet, have your JavaScript console open and see what it logs.

the jQuery closest function already provides the feature you are looking for, no need to reinvent the wheel:
function findTheDiv(e) {
var res = $(elem).closest('div.findme')
if (res. length) {
console.log('found it', res)
return true
}
console.log('the image is not inside a `div.findme`')
return false
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="findme">
<table>
<tr>
<td>
<img id="image" src="image.png" onclick="findTheDiv(this)" />
</td>
</tr>
</table>
</div>

Related

jquery data-attribute set not working

I'm trying to find a 'tr' element with matching data-title value and set data-qty value for that element.
Here's what I tried to do:
var menu_type = data.type;
switch (menu_type) {
case 'breakfast':
var menu_selector = '#breakfast-form';
break;
case 'snacks':
var menu_selector = '#snacks-form';
break;
default:
var menu_selector = '#breakfast-form';
}
for (var key in data.order) {
if (data.order.hasOwnProperty(key)) {
var find_row = $(menu_selector).find('tr[data-title="' + key + '"]').data('qty', data.order[key]);
}
}
console.log(data);
data.order is an array object with {Coffee: "1"}.
And here's my <tr> html:
<div id="breakfast-form">
<table class="orderTable">
<tbody>
<tr data-qty="9" data-title="Coffee">
<td></td>
</tr>
</tbody>
</table>
</div>
Where am I going wrong?
I think this is what you're looking for. You need to use .attr vs .data if you want to assign a data attribute to an element.
var selectors = {
breakfast: '#breakfast-form',
snacks: '#snacks-form'
};
function test(data) {
var menuType = data.type,
cssSelector = selectors[menuType || selectors.breakfast],
menu = $(cssSelector);
for(var key in data.order){
menu.find('tr[data-title="' + key + '"]').attr('data-qty', data.order[key]);
}
}
test({
type: 'breakfast',
order: {
Coffee: "1"
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="breakfast-form">
<table class="orderTable">
<tbody>
<tr data-qty="9" data-title="Coffee">
<td>test</td>
</tr>
</tbody>
</table>
</div>
There is a difference between the data attribute and the data properties.
The HTML markup attribute is used to set the DOM element properties on parse.
And the .data() method accesses the property directly.
From the documentation: «The data- attributes are pulled in the first time the data property is accessed and then are no longer accessed or mutated »
Run the snippet below and inspect the markup.
setInterval(function(){
var count = $("#test").data("count");
console.log(count);
count++;
$("#test").data("count",count);
},1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="test" data-count="0">Test div</div>
If you want to "see" your changes in the markup, you have to update the markup attribute using .attr("data-whatever", "new value");.
Inspect the snippet below now.
setInterval(function(){
var count = $("#test").attr("data-count");
console.log(count);
count++;
$("#test").attr("data-count",count);
},1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="test" data-count="0">Test div</div>
Note that there is an efficiency price on insisting to "see" the markup updating.
Since you mentioned that data.order is an array of object with {Coffee: "1"}, here the key in for-loop will return the index of the array i.e. 0,1,2...
To fix that, you can do something like this:
for(var index in data.order) {
key = Object.keys(data.order[index])[0];
value = Object.values(data.order[index])[0];
if(data.order.hasOwnProperty(index)){
var find_row = $(menu_selector).find('tr[data-title="'+key+'"]').attr('data-qty', value);
}
}
Also you were using .data instead of .attr

Button to change color of <td>

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>

jQuery Click Event for Dynamically Created Links Not Working

I am displaying a list of users in a table. Then, I have a button to allow a user to view more details about a specific user. However, I am having a hard time getting the ID for the user that is clicked on. I am not sure why it's not working. What am I doing wrong? I tried several options, and none of them work.
Partial code of how data the links are generated in my view.
if (Model != null) {
if (Model.Count() > 0) {
foreach (var item in Model) {
<tr>
<td><div class="centerText">#item.UserID</div></td>
<td><div class="centerText">#item.FirstName</div></td>
<td><div class="centerText">#item.LastName</div></td>
<td><div class="centerText">Details</div></td>
</tr>
}
}
}
My jQuery function
$(function () {
$('.Detail').on('click', function (event) {
var dt = $(this).attr('id');
console.log('dt');
});
});
I also tried it this way:
if (Model != null) {
if (Model.Count() > 0) {
foreach (var item in Model) {
<tr>
<td><div class="centerText">#item.UserID</div></td>
<td><div class="centerText">#item.FirstName</div></td>
<td><div class="centerText">#item.LastName</div></td>
<td><div class="centerText">Details</div></td>
</tr>
}
}
}
Here is the Javascript function that I created. It kept giving
function test(e){
console.log(e);
};
I get this error:
0x800a1391 - JavaScript runtime error: 'test' is undefined
updated on 11/21/15 #7:53 AM EST
I removed the for loop and created a single cell with 1 click button. The click event is not registered. I tried it with 'on', 'live', and 'delegate' with no success.
<div class="table table-responsive" style="width:100%;height:100%;">
<table class="table table-bordered table-condensed table-striped">
<thead>
<tr>
<th><div class="centerText">Date Created</div></th>
<th colspan="2"></th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="6"><div class="centerText">Detail</div></td>
</tr>
</tbody>
</table>
</div>
#section Scripts {
<script type="text/javascript">
$('.table tbody tr td div').delegate('.Detail','click', function ()
{
console.log('you click me');
});
</script>
}
You are trying to get the attribute id which doesn't exist. Use below to get data-id
$(function () {
$('.Detail').on('click', function (event) {
var dt = $(this).data('id');
console.log(dt);
});
you can also use
var dt = $(this).attr("data-id");
Second one (remove var):
function test(e){
console.log(e);
};
Partial code of how data the links are generated in my view. change id instead of data-id.
if (Model != null) {
if (Model.Count() > 0) {
foreach (var item in Model) {
<tr>
<td><div class="centerText">#item.UserID</div></td>
<td><div class="centerText">#item.FirstName</div></td>
<td><div class="centerText">#item.LastName</div></td>
<td><div class="centerText">Details</div></td>
</tr>
}
}
}
My jQuery function
$(function () {
$('.Detail').on('click', function (event) {
var dt = $(this).attr('id');
console.log('dt');
});
});
I also tried it this way:
if (Model != null) {
if (Model.Count() > 0) {
foreach (var item in Model) {
<tr>
<td><div class="centerText">#item.UserID</div></td>
<td><div class="centerText">#item.FirstName</div></td>
<td><div class="centerText">#item.LastName</div></td>
<td><div class="centerText">Details</div></td>
</tr>
}
}
}
Here is the Javascript function that I created. It kept giving. (Remove var before function).
function test(e){
console.log(e);
};
Here is how I reproduced your problem with JavaScript runtime error: 'test' is undefined.
Scenario
I guess that you've defined the function test probably in your jQuery DOM ready function $(function(){...}.
If so, the function test is undefined because by the time the DOM is loading, AND the event handlers on DOM elements are being registered (in your case the onclick in the link), the function test is not yet known to the document, and therefore undefined.
Solution
Try to move your test function's declaration outside of jQuery's DOM ready function. That is,
$(function(){
//code that has to run once the DOM is ready
});
function test(e){
console.log(e);
}
DEMO
I found what was causing the problem. I had a modal popup within the form. I was looking to add a textarea, so I added this code '
<textarea name="reasonForArchiveText" id="reasonForArchiveText" />
That's the code that was preventing me from getting the click event. As I was playing around with the code, I commented out the modal popup, and things started to work. Then, I commented section of the modal until I finally found the culprit. The minute that I commented it out, the code works.

Building an anchor menu automatically with jQuery

I need some help for doing a menu built automatically with jQuery.
I have the following HTML structure
<table width="99%" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td height="20">Descripción</td>
</tr>
<tr>
<td height="20">Preguntas Frecuentes</td>
</tr>
<tr>
<td height="20">Incompatibilidades</td>
</tr>
</tbody>
</table>
...
<a name="descripcion"></a>
<h1>Descripcion</h1>
...
<a name="preguntas"></a>
<h1>Preguntas</h1>
In this case the anchor "incompatibilidades" doesn't exist, so what I need is to create a jQuery script which look for any "a" tag which has its corresponding link.
The result I expect is the following:
<table width="99%" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td height="20">Descripción</td>
</tr>
<tr>
<td height="20">Preguntas Frecuentes</td>
</tr>
</tbody>
</table>
I'll appreciate your help!
If I understood correctly, you could do something like this:
var menu = $("#menu");
$("a").each(function() {
var $this = $(this);
var name = $this.attr("name");
if (typeof(name) !== 'undefined') {
var links = $("a[href='#"+name+"']");
var link;
if (links) {
link = links.eq(0);
}
if (link && typeof(link) !== 'undefined') {
menu.append("<tr><td><a href='#"+name+"'>"+link.text()+"</a></td></tr>");
}
}
});
You have to add "menu" id in a new table to create what you expect.
If you would like to remove the the table row which contains the mentioned anchor tag which does not exist, you could use:
$(document).ready(function() {
$('a[href="#incompatibilidades"]').closest('tr').remove(); // Or detach, possibly
});
If you would like to add in an h1 + a and append it to your DOM, you could use:
$(document).ready(function() {
var anchor = $('<a></a>', { 'name' : 'incompatibilidades' });
var h1 = $('<h1></h1>', { text: 'incompatibilidades' });
// Append these to the DOM here.
});
First, you shouldn't be using named anchors, but ids instead (the "name attribute on the a element is obsolete1"), to give:
<h1 id="descripcion">Descripcion</h1>
...
<h1 id="preguntas">Preguntas</h1>
Also, using a <table> element to present a list is a little non-semantic, since it's non-tabular information; instead use an ordered list, <ol>. So, with that in mind, I'd suggest the following jQuery:
$('h1[id]').each(function() {
var target = this.id;
$('#toc').append(function() {
return '<li>' + target + '</li>';
});
});
#toc {
text-transform: capitalize;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ol id="toc"></ol>
<h1 id="descripcion">Descripcion</h1>
...
<h1 id="preguntas">Preguntas</h1>
This approach is based on an assumption that you want to build a table of contents to link to those elements that are on the page.
Notes:
http://www.w3.org/TR/html-markup/a.html#a-constraints.
Without testing, and if I get your question correct - you are looking for something like this:
$().ready(function() {
// scan all links in your menu
$('table').find('a').each(function() {
// grep href attribute
var target = $(this).attr('href');
// element does not exist?
if(! $(target).length) {
// remove parent row
$(this).closest('tr').remove();
}
});
});
And - as #David Thomas mentioned correctly, you shouldn't be using named anchors, but ids instead - if you do so, you can use the anchor ('#xyz') directly as id selector as I did in the function above.

How to remove the parent element using plain Javascript

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.

Categories