Traversing up, then back down the DOM - javascript

I have a click event setup and inside its code block I'm storing the value of certain sibling elements. Right now if I wanted the text inside the .title span after clicking the .play button I have to work my way up two levels and back down to the .title.
I was wondering what would be a better way to access information from sibling elements wrapped in two or more parent divs?
HTML
<table>
<tr>
<td>
<button class="play">Play</button>
</td>
<td>
<span class="number">01.</span>
</td>
<td>
<span class="title">Track 1</span>
</td>
</tr>
<tr>
<td>
<button class="play">Play</button>
</td>
<td>
<span class="number">02.</span>
</td>
<td>
<span class="title">Track 2</span>
</td>
</tr>
</table>
JS
$(function() {
$(".play").on("click", function() {
var number = $(this).parent().parent().find(".number").text(),
title = $(this).parent().parent().find(".title").text();
console.log(number + title);
});
});

You could use jQuery's closest() function.
var number = $(this).closest('tr').find(".number").text(),
title = $(this).closest('tr').find(".title").text();

You can use closest() to go back to a common parent
var number = $(this).closest('tr').find(".number").text(),
title = $(this).closest('tr').find(".title").text();
fiddle

Related

Hide a parent element if ID contains specific text string with vanilla Javascript

I'm wanting to hide a parent <tr> tag where a grandchild <span> tag has an ID with a specific string.
Let's say I want to check for the string "test123" in the ID, e.g.
<table>
<tr id="this_is_a_test456">
<td>
<span>
<span>
<span>
</span>
</td>
</tr>
<tr> <<<--- THIS ROW SHOULD BE DELETED
<td>
<span>
<span id="this_is_a_test123">
<span>
</span>
</td>
</tr>
</table>
Find the <span> within a <tr> by partial ID and if it exists, select the parent row and remove it
let idPartial = 'test123'
let span = document.querySelector(`tr span[id*="${idPartial}"]`)
if (span) {
span.closest('tr').remove()
}
<table border="1">
<tr id="this_is_a_test456">
<td>
<span>
<span>My row stays<span>
</span>
</td>
</tr>
<tr>
<td>
<span>
<span id="this_is_a_test123">My row goes<span>
</span>
</td>
</tr>
</table>
See
Attribute selectors
Element.closest()
ChildNode.remove()
The above finds the first element matching your condition ("id attribute contains"). If you wanted to do this for all matching <span> elements, use
let idPartial = 'test123'
document.querySelectorAll(`tr span[id*="${idPartial}"]`).forEach(span => {
span.closest('tr').remove()
})
As per Why does jQuery or a DOM method such as getElementById not find the element?, make sure your code runs after the document has loaded.

Extracting data between 2 tags in Javascript

I'm a js newbie. I'm trying to get a table from a really old and outdated webpage that is continually updated (locally) and add it to a different page.
I need to extract table 1 from the following example. Bonus points if you can explain how your solution works.
<html>
<head>
</head>
<div> This is table 1 </div>
<table>
<tr>
<td>
<a>
</a>
</td>
</tr>
</table>
<div> This is table 2 </div>
<table>
<tr>
<td>
<a>
</a>
</td>
</tr>
</table>
</html>
Thank you!
Typically you would give the target element a unique ID, and target it with document.getElementById('[target]'):
var element_1 = document.getElementById('one');
console.log(element_1);
<div id="one">This is table 1</div>
<table>
<tr>
<td>
<a>
</a>
</td>
</tr>
</table>
<div id="two">This is table 2</div>
<table>
<tr>
<td>
<a>
</a>
</td>
</tr>
</table>
If you don't have access to a unique ID in the HTML, but do have an applicable class, you can use document.getElementsByClassName('[target]'), which returns a collection of all elements with the desired class name:
var elements = document.getElementsByClassName('target');
console.log(elements[0]);
console.log(elements[1]);
<div class="target">This is table 1</div>
<table>
<tr>
<td>
<a>
</a>
</td>
</tr>
</table>
<div class="target">This is table 2</div>
<table>
<tr>
<td>
<a>
</a>
</td>
</tr>
</table>
If you don't have access to either a unique ID or but have access to jQuery, it's quite simple to tranverse the DOM with .find('div'), which returns an array of all the <div> nodes. From there you can simply specify the desired index:
var element_1 = $(document).find('div')[0];
var element_2 = $(document).find('div')[1];
console.log(element_1);
console.log(element_2);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>This is table 1</div>
<table>
<tr>
<td>
<a>
</a>
</td>
</tr>
</table>
<div>This is table 2</div>
<table>
<tr>
<td>
<a>
</a>
</td>
</tr>
</table>
Alternatively, with raw JavaScript, it is possibly to target elements with .childNodes (made easier with .firstElementChild). You still need to work from a 'unique' point, and in this case, you'll want to work from body, or even document itself.
Note that in this example, childNodes[5] pertains to the second <div>, as each 'node' is prefaced by a descriptor of that node. As such, childNodes[1] references the first <div>, childNodes[3] references the <table>, and childNodes[5] references the second <div>.
var element_1 = document.body.firstElementChild;
var element_2 = document.body.childNodes[5];
console.log(element_1);
console.log(element_2);
<div>This is table 1</div>
<table>
<tr>
<td>
<a>
</a>
</td>
</tr>
</table>
<div>This is table 2</div>
<table>
<tr>
<td>
<a>
</a>
</td>
</tr>
</table>
Hope this helps! :)
Another shorter way is using DOMParser.
DOMParser.parseFromString will parse your html code into DOMDocument object. DOMDocument object has body object. And in turn body has children. Your table1 is the 2nd child in that list .
let source = "..." //your html text above
// method 1: use DOMParser
let dom = (new DOMParser()).parseFromString(source, 'text/html')
let table1 = dom.body.children[1]
Try this https://codepen.io/minht/pen/EXbgXY?editors=0010#0

How to apply CSS to children of TR based on TD content?

I'd like to hide a <div> or <td> inside the <tr> based on the content inside that <tr>.
If Stackoverflow is found inside a <tr>, hide .buttons from that <tr>.
This is what I've got so far.
<table class="sites">
<tbody>
<tr>
<td>
<div class="name">Stackoverflow</div>
</td>
<td>
<div class="buttons">
buttons
</div>
</td>
</tr>
<tr>
<td>
<class name="">Stackexchange</class>
</td>
<td>
<div class="buttons">
buttons
</div>
</td>
</tr>
</tbody>
</table>
var t = $(".sites tr .name:contains('Stackoverflow')");
var d = t.parent('tr').children('.buttons');
d.css( "display", "none" );
I've made a fiddle: https://jsfiddle.net/3jk8e3b2/3/
Your traverses are not going to appropriate levels.
parent() is only immediate parent element, children() are only immediate child nodes
In your case parent of .name is a <td> not <tr> and the buttons are not immediate children of <tr> either.
Use closest() or parents() to allow going up more than one level. Use find() to allow going deeper than children()
Try:
var t = $(".sites tr .name:contains('Stackoverflow')");
t.closest('tr').find('.buttons').hide();
DEMO

Getting the text value of a hidden span tag

I have a table with columns of data (name, age, email) and I have a single modal window that is hidden and only appears when the user clicks "Detail" along side each row.
The data that needs to be populated in the modal is in hidden span tags with classes such as hide-name etc.
HTML:
<tr class="xrow row-2">
<td>Fisher, Baker</td>
<td>2 notes</td>
<td>Review</td>
<span class="hide hidden-name">Fisher, Baker</span>
<span class="hide hidden-date">2014-03-20</span>
<span class="hide hidden-time">14:00:00</span>
</tr>
This is my JS that I have used, however when I call on the name variable it returns nothing.
$('.xrow').on("click", '.btn-review', function () {
var name = $(this).closest('span.hidden-name').text();
// alert(name);
}
this in your code refers to the .btn-review element not the tr, you should at first select the closest tr element:
var name = $(this).closest('tr').find('span.hidden-name').text();
edit: Your markup is invalid, tr element can only have td child element, you should wrap the span elements with td elements, browsers will render this markup differently. After changing the markup the above snippet should work.
I would suggest moving the spans to the td element that has the button as it's child and then use $(this).siblings('span.hidden-name').text() which is more efficient than using closest and then find.
<tr class="xrow row-2">
<td>Fisher, Baker</td>
<td>2 notes</td>
<td>
Review
<span class="hide hidden-name">Fisher, Baker</span>
<span class="hide hidden-date">2014-03-20</span>
<span class="hide hidden-time">14:00:00</span>
</td>
</tr>
I think I've figured what you want:
$('.xrow').click(function () {
var name = $(this).find('span.hidden-name').text();
})
You just have to search the element you want, within the contents of the element you clicked on.
you should wrap your spans with any td. for example last td.
<td>
Review
<span class="hide hidden-name">Fisher, Baker</span>
<span class="hide hidden-date">2014-03-20</span>
<span class="hide hidden-time">14:00:00</span>
</td>
and you can reach with:
$('.xrow').on("click", '.btn-review', function () {
var name = $(this).parents('.xrow').find('span.hidden-name').text();
alert(name);
});
http://jsfiddle.net/V4z8S/2/

Quickest way to find an element with jQuery

Given the following html:
<tr>
<td>Content</td>
<td>Content</td>
<td>Content</td>
<td><img id="imgProductPurchased" runat="server" visible="true" alt="Product Purchased" title="Product Purchased" src="/sitecore/shell/Themes/Standard/Applications/16x16/checkbox.png" /></td>
<td>
<asp:PlaceHolder ID="plhPurchased" runat="server">
<span class="roundButton roundButtonLarge"><a id="hypPurchased" class="registryPurchased" href="#" title="Mark product as purchased" runat="server"><span>
<em class="registryPurchased"></em>Purchased</span></a> <span class="buttonEndLarge">
</span></span>
</asp:PlaceHolder>
</td>
</tr>
<tr>
Repeats above
</tr>
I have a click event on "hypPurchased". When that event fires, I need to access the plhPurchased element, and "imgProductPurchased" elements of THAT row.
EDIT:
I should have stated that this is being built with ASP.NET, and as such, the id's are all unique.
If the click event is on the particular row and the element is a child of that row, you can use context to get the result.
$(".myRow").click(function() {
var somethingFromMyRow = $(".myChildClassName", this).text();
alert(somethingFromMyRow);
});
Please note, you shouldn't be duplicating the same ID anywhere on your page, so the example I have supplied uses a class name instead - so imagine you have HTML like this for your example.
<tr class="myRow">
<td><span class="myChildClassName">Some Text In Row 1</span></td>
<td>More Stuff</td>
</tr>
<tr class="myRow">
<td><span class="myChildClassName">Some Text In Row 2</span></td>
<td>More Stuff</td>
</tr>
<tr class="myRow">
<td><span class="myChildClassName">Some Text In Row 3</span></td>
<td>More Stuff</td>
</tr>
id's can't be duplicated in HTML,
Anyway, what you need to do is get to a parent element (go up in the hierarchy until you get the parent element that encompasses the "current" row), then you run the query against it:
jQuery( your_query_string, parent )
Where parent is something you can get using:
parent = query.parent()
For instance:
function click_handler(element)
{
parent = jQuery(element).parent()
name = jQuery(".name", parent)
// do stuff
}
name = jQuery(".name", parent) will get all elements with class name under the parent element.
has Hasen said, you cant duplicate id's in html.
so, apply a class to "plhPurchased" and then:
at the hypPurchased you put onclick="yourFuntion(this)"
function yourFuntion(elem)
{
var tr=$(elem).closest('tr');
var _imgProductPurchased = tr.find('img');
// if you have more then a img per row, you should apply a class to the image to and get it by:
// tr.find('.imgClass');
var _plhPurchased=tr.find('.thatClassYouApplyed');
}

Categories