Element.querySelector for the element's direct child - javascript

I have some JS constant with HTML element (for example Div). I need to know if the element contains some HTML structure. For example, here is my HTML:
<div id="container">
<table class="cls1 cls2">
<tbody class="cls3 cls4">
<tr class="cls5 cls6">
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<div></div>
<span></span>
I have JS constant with <div id="container"> element.
For example:
const div = document.querySelector('#container');
It is just an example. Actually the div doesn't contain "container" id. And I get this element from some function, so I don't know the element's CSS selector.
I need to know, if the element contains this CSS selector: table.cls1.cls2 > tbody.cls3.cls4 > tr.cls5.cls6 > td and the table.cls1.cls2 must be the direct child of the div. It would be great to use something like this:
const ok = div.querySelector('> table.cls1.cls2 > tbody.cls3.cls4 > tr.cls5.cls6 > td');
But it is not a valid selector (which starts with ">").

You can make use of :scope pseudo class to target self and then write selectors for direct children
const ok = div.querySelector(':scope > table.cls1.cls2 > tbody.cls3.cls4 > tr.cls5.cls6 > td');

Related

Get div value from class name

I have a very large HTML that contains lots of divs with the same name, I want a way to only filter or extract that value from that div.
Here is an example:
<td class="last">
<div class="container-relative">
<div class="name" title=""User" <John Appleseed>"></div>
<div class="date">9/17/2019</div>
<div class="tool"></div>
</div>
</td>
I need to extract only what's between <John Appleseed>, in this case is 'John Appleseed'.
You could use querySelectorAll to take all the elements with class name, then get the title attribute with getAttribute, and finally use a regular expression to match text between <>.
document.querySelectorAll('.name').forEach(item => {
let title = item.getAttribute('title');
console.log(title.match(/\<.*\>/));
});
<td class="last">
<div class="container-relative">
<div class="name" title=""User" <John Appleseed>"></div>
<div class="date">9/17/2019</div>
<div class="tool"></div>
</div>
</td>
var divs=[];
for(i=0,j=0,obj=document.getElementsByClassName("name");i<obj.length;i++)
if(obj[i].title.includes("John Appleseed") &&
/* obj[i].title.split("\"")[2].trim()=="<John Appleseed>" && */
obj[i].tagName.toLowerCase()=="div"){
divs[j++]=obj[i];
}
console.log(divs);
separate your div using div ID. Then get your respective div using that value of ID. Then in javascript you can use getElementByID.
You can use Xpath,
.//div[contains(#class, 'Test')]
Then extract you required text from it.

Javascript/jQuery - Each skip all children

I'm getting all the elements on the document:
$("*").each(function(){
var el = $(this);
});
What I need is to get all the elements but the children elements. I mean this:
<div> <!--GET IT-->
<div></div> <!--DON'T GET IT-->
</div>
<div> <!--GET IT-->
<div></div> <!--DON'T GET IT-->
<label></label> <!--DON'T GET IT-->
</div>
How can I filter that?
You can target the parent element of outermost div elements and then use immediate child selector to get first level child element.
Let us assume you have above markup in body container. Then you can use
$('body > *').each(function(){
var el = $(this);
});
You can use this
$('body > * ').each();
This targets all elements childrens of body, but don't target the childrens of the elements.
Look this: https://api.jquery.com/child-selector/
$("parent > child").each(function(){
$(this) /* children */
});

cant get text from an element in jQuery

I have a HTML setup as follows and am trying to use jQuery to access the textin the font field. The table has multiple rows, hence the first line in the jQuery, for some reason I'm getting an empty string returned for the title variable. Thank you for your help!
HTML
<table class="table">
<tbody>
<tr>
<td class="head">
<a href="link" target="_self">
<p>
<font>SomeText</font>
</p>
</a>
</td>
</tr>
</tbody>
</table>
jQuery
$('.table').each(function(){
$(this).filter(function(){
var data = $(this);
title = data.children(".head").text();
json.array.push({
"title" : title
});
})
})
.head is not a child of .table. So .children(".head") will not return any elements. You should use .find instead.
Also, the .filter seems unnecessary:
$('.table').each(function(){
var data = $(this);
title = data.find(".head").text();
json.array.push({
"title" : title
});
})
Your element with class head has no text in it, you need to adjust your selector to get the actual font element, like this:
data.children(".head font").text();

Selecting first child based on attributes

I wanna be able to select a specific set of child in which an attribute is defined.
But how to select childs which are first child of the root selector that having the attribute data-role
first-of-type selector doesn't work due to the type of the element.
Here we have a sample of the DOM.
<body>
<div data-role="ca:panel" title="foo">
<div data-role="ca:vbox" width="100%">
<div data-role="ca:form">
<div data-role="ca:formitem">
<div data-role="ca:hbox">
<input data-role="ca:textinput">
<div data-role="ca:menu"></div>
</div>
</div>
<div data-role="ca:formitem">
<input data-role="ca:passwordinput">
</div>
<div data-role="ca:formitem">
<select data-role="ca:combobox">
<option>[...]</option>
</select>
</div>
</div>
<table>
<tbody>
<tr>
<td>
<span data-role="ca:label"></span>
</td>
<td>
<button data-role="ca:button"></button>
</td>
<td>
<button data-role="ca:button"></button>
</td>
</tr>
</tbody>
</table>
</div>
</body>
My filter should select only
<div data-role="ca:form">
<span data-role="ca:label"></span>
<button data-role="ca:button"></button>
<button data-role="ca:button"></button>
It should work in any case, meanings, it shouldn't be linked to a specific structure of the dom and must use data-role as 'selector'.
I'm not a relevant jQuery developer. I tried some selector such as $('[data-role]:first-of-type'); but it doesn't work.
Do you have an idea to select the right set of child.
Note: Finding the first parent is not a concern.
It is possible to do this generically using a filter, so long as you have a start node:
JSFilter: http://jsfiddle.net/TrueBlueAussie/2uppww9s/5/
var root = $('[data-role="ca:vbox"]');
var matches = root.find('[data-role]').filter(function(){
return $(this).parentsUntil(root, '[data-role]').length == 0;
});
alert(matches.length);
You can use the :first pseudonym to select the first occurance of a element like for example:
var elm = $('*[data-role="ca:form"]:first');
this will select * any type of DOM-element, with the data-role that matches "ca:form"
Since you want to return two buttons with the same data-role, we cant use ":first" for that. You would have to get the first child of a that matches in that case
var elm = $('td').children('button[data-role="ca:button"]:first');
This will look through the child elements of all TD-tags and find the first button with data-role matching "ca:button"
If you want first of all overall specifications, then you can simply use selector on all three tag types and filter them as so:
$('div, span, button').filter(function(i){
if (this.tagName == 'DIV' && $(this).data('role') == 'ca:form') return true;
if (this.tagName == 'SPAN' && $(this).data('role') == 'ca:label') return true;
if (this.tagName == 'BUTTON' && $(this).data('role') == 'ca:button') return true;
}).first();
Using .first grabs the first of them.
Also, filter can be used in a million ways to get what you want and sounds like it may get you to what you need. Just set what you're filtering for in an if/for/switch statement and return true on items that match.
jsFiddle
However, if you wanted first of each you could do something like:
$('div[data-role="ca:form"]:first, span[data-role="ca:label"]:first, button[data-role="ca:button"]:first')
If variable driven in someway, just use string concatenation.
jsFiddle

How to add div to span inside this table row?

I have a table row as such:
<tr class="song-row song-row-selected" data-id="1">
<td data-col="title">
<span class="song-content">
<img src="img/cover3.jpg" />
Song Title
</span>
</td>
<td>3:37</td>
<td>song artist</td>
<td>song album</td>
<td>23</td>
</tr>
I want to add a div to indicate that the song is paused (surrounded by *):
<tr class="song-row song-row-selected" data-id="1">
<td data-col="title">
<span class="song-content">
<img src="img/cover3.jpg" />
Song Title
*<div class="song-indicator loading"></div>*
</span>
</td>
<td>3:37</td>
<td>song artist</td>
<td>song album</td>
<td>23</td>
</tr>
I was hoping to use JQuery. So far I have:
function displayPause() {
$('tr.song-row.song-row-selected:first').each(function() {
$(this).siblings('td span.song-content').add('<div class="song-indicator paused"></div>');
});
}
Needless to say, it doesn't add the div. Also, I would like a function for me to easily remove the div from the span. Does anyone know where to point me in the right direction?
You should be using append as well as children, not siblings
$(this).children('td span.song-content').append('<div class="song-indicator paused"></div><input type="button" class="removeDiv" value="Remove"/>');
I also added a button right next to your div, clicking this will remove that div with this code:
$(document).on("click", ".removeDir", function() {
$(this).prev(".song-indicator").remove();
$(this).remove();
});
append is what you want:
$(this).find('td span.song-content')
.append('<div class="song-indicator paused"></div>');
This will ... append the div to the end of your span.
Also, as tymeJV says, your td is not a sibling of your tr; it's a child. Use either children, or find to grab it.
And to remove it, you'd use remove. If I understand your app correctly, it should be something like this:
$('tr.song-row.song-row-selected:first')
.find("div.song-indicator.paused").remove();
Here a litte sample on jsfiddle
$("tr.song-row-selected:first td span.song-content").append("*<div class='song-indicator loading'></div>*");

Categories