How to select the next immediate child using querySelector? - javascript

I want to loop through a div and store the <h4> and <ul> inside an object.
And I already used querySelectorAll but that will select all h4 or ul elements.
In the picture you can see I'm selecting the immediate <h4> and <ul> child, likewise I want to select the next <h4> and <ul> elements and store it in an object.

You can still use querySelectorAll and choose the correct index (next will be index 1)
document.querySelectorAll('#main > ul')[1]
document.querySelectorAll('#main > h4')[1]
Example proof of IMDB web
const secondH4 = document.querySelectorAll('#main > h4')[1]
const secondUL = document.querySelectorAll('#main > ul')[1]
console.log(secondH4, secondUL)
<div id="main">
<h4>11 August 2020</h4>
<ul>
<li>
Valley of the Gods (2019)
</li>
</ul>
<h4>14 August 2020</h4>
<ul>
<li>
Spree (2020)
</li>
<li>
Endless (2020)
</li>
<li>
The Bay of Silence (2020)
</li>
</ul>
</div>
NOTE
By using nextSibling you'd need more logic since nextSibling does not select the next h4 or next ul it selects whatever DOM element is next to the current one

You should probably select all 'h4' and 'ul' elements into their own collections, identify the current element in these collections and simply pick the following element. Here is a small snippet showing how to find the next <h4>:
const allH4s= [...document.querySelectorAll("h4")];
// assuming a <h4> has been selected:
const firstH4=document.querySelector("h4"),
// then nextH4 will be the immediately following h4 element in the document:
nextH4=allH4s[allH4s.indexOf(firstH4)+1];
[... collection] creates an Array from a collection. This is necessary, as we need to access the Array-method indexOf().
You can do a similar thing for your <ul>s.

Related

Jquery find('*') doubling A tags

I'm slightly confused by the Jquery find('*') on an element finding A tags. My example code is below:
<ul>
<li id="cell1" data-link="Page 1">
<p>Example text</p>
</li>
<li id="cell2" data-link="Page 2">
<h2 class="story-body__crosshead">More from our Diet Debate series:</h2>
<p>Read: Is breakfast a waste of time?</p>
<p>Watch: How healthy is your breakfast?</p>
</li>
<li id="cell3" data-link="Page 3">Cell 3</li>
<li id="cell4" data-link="Page 4">Cell 4</li>
</ul>
Js Code
$(elem).find('*').each(function(){
if ($(this).html().indexOf('breakfast') > 0){
alert($(this).html());
}
});
Alert is however alerting twice per A tag. It shows the inner text and the outer text (full a html). However I am relying on moving elements and replacing them so this code ends up outputting links twice on the same page. Am I missing something obvious?
Your code is matching the a tags and any ancestors of the a tags because * matches all DOM elements within the elem (which is your LIs). In your example it will match the p tags as well as the a tags.
Use a scoped selector that targets only the a tags:
e.g.
// Elem here is the li about
$("a", elem).each(function(){
if ($(this).html().indexOf('breakfast') >= 0){
alert($(this).html());
}
});
Or simpler using :contains:
$("a:contains(breakfast)", elem).each(function(){
alert($(this).html());
});
Note: Your code only allows for text containing breakfast but not Breakfast (e.g. if it was at the start and capitalized) as the check is case-sensitive.

Selecting an element created using document.createElement jquery/javascript

I am creating a number of div and ul elements using document.createElement. In a case, when I am creating these elements I need to take reference of one of those elements that I created above and assign it as the parent to element that's next in line to be created.
I have the id (e.g "idoftheelement") of the created element but when I do
$('#idoftheelement')
I don't get the element.
Is there a possibility to get the element. If yes how ?
Edit:
Below is html structure I am trying to generate based on a JSON input data. Every element in the JSON array could have a child array of elements. All the elements will have the same markup and the difference is only in where they are getting placed. I have to construct this in a recursive way i.e for every JSON element check if child elements(and the child elements could also contain child elements) are present, if yes then i should append these child elements to corresponding parent thread block. This is why I need to know if there is a direct way to get the reference of parent element that is in context to the current element so that It can be appended.
<div id="comment-12345">
<div id="threads-block-12345"
<ul id="thread-12345">
<li id="thread-item-12346">
<div id="comment-12346">
<div id="threads-block-12346"
<ul id="thread-12346">
<li id="thread-item-12347">
<!--keeps growing if there till all the children are processed-->
</li>
</ul>
</div>
</div>
</li>
<li>
<div id="comment-xyz">
<div id="threads-block-xyz"
<ul id="thread-xyz">
<li id="thread-item-xyz">
<!--keeps growing if there till all the children are processed-->
</li>
</ul>
</div>
</div>
</li>
</ul>
</div>
The code $('#idoftheelement') tells me you are using jQuery, so you shouldn't be using document.createElement. What you need to do is create the element using jQuery and reference it by that variable. For example:
var $node = $("<div id='" + id + "'>")
$node.append( ... new elements ... )

jQuery Prepend Open Tag Append Closing Tag

Firstly, I am familiar with .wrapAll() and that is not what I need. I have some markup that I am not able to change and I need to wrap everything in a <li>.
Here is what I am trying to do:
$('nav[role="breadcrumb"] ul a').wrap('<li></li>');
$('nav[role="breadcrumb"] ul li:last').after('<li>');
$('nav[role="breadcrumb"] ul').append('</li>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav role="breadcrumb">
<ul class="clearfix">
Home
Health Care Professionals Healthy Choices Cholesterol Kits
</ul>
</nav>
The problem is that jQuery closes each of these <li> tags. Here is the original markup:
<nav role="breadcrumb">
<ul class="clearfix">
Home
Health Care Professionals Healthy Choices Cholesterol Kits
</ul>
</nav>
As you can see, I have some loose text at the bottom of this <ul> and I am trying to get it wrapped in an <li>.
.contents() will get all the children, including the text nodes
$('nav[role="breadcrumb"] ul').contents().filter(function() {
return $.trim($(this).text())!=="";
}).wrap('<li/>');
EDIT: Added the filter method to get rid of the whitespace text nodes
Try creating your <li> first and then append your selector to it:
var $li = $('<li>').append('nav[role="breadcrumb"] ul a');
Then use $li to replace or append anywhere you like.
jQuery only works with complete elements, you can't append just a closing or opening tag.
If the ul doesn't have any other list items, you could simply use wrapInner
$('nav[role="breadcrumb"] ul').wrapInner("<li />");
If it does contain LI's, the easiest way would be to detach them, wrap inner, then append them.
var $lis = $('nav[role="breadcrumb"] ul > li').detach();
$('nav[role="breadcrumb"] ul').wrapInner("<li />").prepend($lis);

Jquery selecting hierarchies

Before I begin this question, if you're new to backbone.js and want to implement the following functionality you have to use the backbone relational model, or at least that's what it seems like.
I'm trying to create a hierarchy that will be implemented through backbone.js and I was wondering how to structure the hierarchy and access the elements. I need to be able to add and remove Lists/Sets/Items and hopefully keep a consistent numbering policy. (List1 would have a displayed name of list1. If I deleted Set1 I would want Set2 to become Set1 while retaining its corresponding items)
List1
^--->Set1
^--->Item1
^--->Item2
^--->Set2
^--->Item1
List2
^--->Set1
^--->Item1
^--->Set2
^--->Item1
^--->Item2
etc.
My question is this: How do you structure this in a way such that a set of functions following the same hierarchy can access them in the most compact and logical manner?
One idea I had:use div and just have your div id be something like id="List"+currentlistnum()+"Set"+currentsetnum()+"Item"+currentitemnum()
Is there a better way to do it than this?
If you have list of items that is semantically a "list", use ordered list(ol) or unordered list(ul). Then if you have sub lists nest more lists.
<ul id="mylist">
<li>
<span>List 1</span>
<ul>
<li>
<span>Set1</span>
<ul>
<li>List1Set1Item1</li>
<li>Item2</li>
<li>Item3</li>
</ul>
</li>
<li>
<span>Set2</span>
<ul>
<li>Item1</li>
<li>Item2</li>
<li>Item3</li>
</ul>
</li>
</ul>
</li>
</ul>
And use jQuery nth Child selector and immediate child > for rest of logic to select particlar elements, so you can keep application logic away from HTML.
$('#mylist > li:nth-child(1) > span').text(); // List1
$('#mylist > li:nth-child(1) > ul > li:nth-child(1) > ul > li:nth-child(1)')
.text(); //List1Set1Item1
If you want a numbering system attached: Example refresing all Set to update its number according to present view:
$('#mylist > li > ul > li > span').each(function(){
var ordinalPositionOfMyParent = $(this).parent().index() + 1;
$(this).text('Set' + ordinalPositionOfMyParent);
});

How to aceess span directly using jQuery

I want to know how to get access of this [span class="myclass"] in below html structure..
<ul>
<li class="first">
<span class="myclass"></span>
<div class="xx">
<span></span>
........
</div>
<li >
<span class="myclass"></span>
<div class="xx">
<span></span>
........
</div>
</ul>
Here I need to write one function in [span class="myclass"], but i cant do it using $(".myclass") [I have few issues] I just want to directly access the span itself.How to do this..?
EDIT:the sln by phoenix is working fine..but lets say(just for my knowledge) the structure is
<li >
<span class="myclass"></span>
<div class="xx">
<li>
<span></span>
</li>
........
</div>
</ul>
so why the span inside 2 nd li(which is under div) is not getting the ref, is it bcoz they are not in the same level..if I need to access them do I need to do some thing like
enter code here
$("li").next(".xx").find(li span:first-child )..or something else is there?
Thanks.
$("li span.myclass")
EDIT: Okay then maybe with
$("li span:first") //EDIT: Don't do that. See below.
apparently :first stops after the first hit. So :first-child is the way to go.
which will select the first span in every li-element. But this can be tricky in case you have other li-elements with spans inside...
EDIT: If you can't use the class you already have, maybe assigning an additional class helps?
<span class="myclass newClass"></span>
...
var spans = $("li span.newClass");
EDIT:
As phoenix pointed out
$("li span:first-child")
returns a list with all span elements that are the first child of a li-element. I don't know if jQuery treats textnodes as child nodes. So if you have a space between <li> and <span>, this might be counted as the first-child. So check if you have any whitespace between your elements beside line breaks.
If span is the first child then you can use
first-child
selector
$("li span:first-child");

Categories

Resources