Javascript DOM,accesing the textnode of the <li>element using nextsibling property - javascript

<body>
<div id="li-container">
<ul>
<li class="hot">item1</li>
<li id="secLi" class="cool">item2</li>
<li class="cool">item3</li>
<li class="cool">item4</li>
</ul>
</div>
<script language="javascript" type="text/javascript">
var secLi = document.getElementById("secLi");
var sib = secLi.nextSibling;
document.write(sib);
//OR //OR //OR //OR //OR //OR //OR //OR
var secLi = document.getElementById("secLi");
var sib = secLi.nextSibling;
document.write((sib).textContent);
</script>
</body>
I want to get the textnode of the third list(li) item using nextSibling property and write in the document.I know I can use "li.textContent" to access it but I want it this way.
No,I am not looking for "nextElementSibling",I want to acess the "textNode" of "secondli" using "nextSibling" property and that is because if I want to get to the "third li",I must use "nextSibling.nextSibling"twice to get to the "third li".(1)First "nextSibling" is for the "text-node" of the "2nd li" and (2)Second "nextSibling" is for the "3rd li".So I am not able to get the text-node of "2nd li" using "next-sibling" once.
I used text-fixer.com to remove other white-spaces and line breaks even then it dosent work.

Are you perhaps looking for nextElementSibling?
var secLi = document.getElementById('secLi');
secLi.nextSibling; // Is a text node.
secLi.nextElementSibling; // Is the <li> you're looking for, so..
secLi.nextElementSibling.textContent; // Gives you "item3"
Update
To better understand why you want nextElementSibling instead of nextSibling look at what the parent <ul> says its childNodes are:
secLi.parentElement.childNodes;
// [#text, <li>, #text, <li>, #text, <li>, #text, <li>, #text]
You don't want the nextSibling because it's just the empty text between list items. You want the next element (list item).
See https://developer.mozilla.org/en-US/docs/Web/API/NonDocumentTypeChildNode/nextElementSibling

the textnode of the li element is a child of 2nd li element.
So the code would be
var sib = secLi.firstChild.textContent;
document.write(sib);
#brianvaughn

Related

Read HTML snippet from DOM and add custom data to it

I'm used to use jQuery to query elements by their id and place inside them or in their attributes some custom data retrieved from a webservice.
But now the data I'll retrieve is an array of objects. So it's not just a matter of adding one data into one element. I need to read a li which has some HTML inside, then replace some elements on this HTML with data from one object.
This has to be done for each object in the array, so I'd need to create a new li from that "template", populate it, then add it to the ul.
I'm able to query the ul, find its li and remove it from DOM, and append multiple lis to it.
But I don't know how, having the li in a jQuery object, make changes on its innerHTML. This is the part I'm lost, as I was still unable to find some solution on Google.
Here's an example: https://jsfiddle.net/r76vpLdg/
How can I create a new object based on template and replace the contents of those 2 spans? I added a second list, with an example of the desired result.
Here's a Vanilla JS solution using a JSON object as data source and template strings.
Unless using jQuery is a must, there is no reason to use it in this case.
<p>template:</p>
<ul id="myListContainer">
</ul>
<button onclick="createTemplateStrings()">
START
</button>
function createTemplateStrings (){
var obj = [
{"name": "John", "weekday" : "Wednesday"},
{"name": "Marry", "weekday" : "Sunday"},
{"name": "Edward", "weekday" : "Friday"},
{"name": "Jack", "weekday" : "Tuesday"}
]
let ul = document.getElementById('myListContainer')
for(let row of obj){
let li = document.createElement('LI')
li.innerHTML = `Hello, ${row.name}, how's your ${row.weekday} ?`
ul.append(li)
}
}
You can create elements "in memory" without them being part of the DOM, build them up, then add them to the DOM as required, eg:
var li = `$("<li>");
li.html(innerHTML);
ul.append(li);
Working example:
var ul = $("ul");
$("button").click(function() {
var li = $("<li>");
li.text("new item");
ul.append(li);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>item</li>
</ul>
<hr/>
<button type='button'>add</button>
To work with an existing "template", you can .clone() an existing li and make changes, one possible solution/example:
var ul = $("ul");
$("button").click(function() {
// create a copy of the "template"
var li = ul.find("li.template").clone().removeClass("template");
// make changes
li.find("span").removeClass("first").addClass("new").text("new");
ul.append(li);
});
li>span.first { color: blue; }
li>span.new { color: green; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li class='template'>This is the <span class='first'>first</span> item</li>
</ul>
<hr/>
<button type='button'>add</button>

Jquery assign second child attribute

Is there a way to assign nested div attribute with variable? Like
<div>
<div>
123456
</div>
</div>
Become
<div>
<div sectionid="123">
123456
</div>
</div>
BTW above component will be created by JavaScript.
I've tried something like this, but it didn't work.
var a = $('<div><div>123456</div></div>');
a.eq(":nth-child(2)").attr("sectionid", "123");
Try this snippet.
//FOR DOM HTML
console.log("FOR DOM HTML");
//1st way
$('#input > div').find('div').attr("sectionid","123");
console.log($('#input').html());
//2nd way
$('#input > div > div').attr("sectionid","321");
console.log($('#input').html());
//JS HTML
console.log("FOR JS OBJECT");
var input = $('<div><div>123456</div></div>');
//1st way
input.eq(0).children().attr('sectionid', '456');
console.log(input[0].outerHTML);
var input = $('<div><div>123456</div></div>');
//2nd way
$(input[0]).children().attr('sectionid', '789');
console.log(input[0].outerHTML);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="input">
<div>
<div>
123456
</div>
</div>
</div>
nth-child(2) maches elements that are the second child element of their parent. This is not the case for your div, it is the first element of the parent div.
.eq finds an element at a specific index. It is not the place to pass a selector.
The child selector, >, will find a child element, i.e. div>div will find a div that is an immediate child of a div.
Note that the code you've provided, $('<div></div>123456<div></div>');, doesn't create a DOM tree like the one you've pasted.
Update, now that the code is edited, the value of a is a div with a child div. Since a.find will perform a search within a, you don't have to use a child selector, but can find the div immediately:
a.find('div')
Just apply attribute to children. No complicated 'find', eq(), etc.
var a = $('<div><div>123456</div></div>');
a.children().attr('sectionid', '123');
$('body').append(a);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Why don't you add it in the first place? Not clear if you add it later!
$(document).ready(function() {
var sectionid = "123";
var a = $('<div><div sectionid="' + sectionid + '">123456</div></div>');
$('body').append(a);
});
div[sectionid]{
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Try this - I have added comments to the code to explain what is happening.
Inspect the element to see that the attribute is added
var a = $('<div><div>123456</div></div>'); // change this to match the structure you want
a.children() // .children gets the direct descendant (which should be the nested div
.eq(0) // gets the first in the array that is returned (if there are multiple direct descendents) - it is a 0 based index selector
.attr('sectionid', '123');
$('body').append(a)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
More information about .children()
More information about .eq()
try it :
$(document).ready(function(){
$("div").eq(1).attr("sectionid","123");
})

Select element by element's content

I have list:
<ul class='mates'>
<li class='m' id='1'>Jakub</li>
<li class='f' id='2'>Vinnie</li>
<li class='m' id='3'>David</li>
</ul>
How can I select 'li' tags "ONE BY ONE" to be checked if their content (between 'li' tags) is equal to 'xyz'.
element = document.getElementsByClassName('.mates').firstChield.innerHTML;
do {
if(){
//do something
}
}while (element = element.nextSibling);
but I'm not getting even far enough to select firstChild. This error is showing in console: "Cannot read property 'innerHTML' of undefined". This needs to be done in plain JavaScript. Any ideas?
<ul class='mates'>
<li class='m' id='1'>Jakub</li>
<li class='f' id='2'>Vinnie</li>
<li class='m' id='3'>David</li>
</ul>
<script>
var mates = document.getElementsByClassName('mates')[0];
for (var i=0; i< mates.childNodes.length; i++){
if(mates.children[i].innerHTML == 'Vinnie') alert("Got you! ID "+mates.children[i].id)
}
</script>
Drop the dot in the parameter. Like this:
element = document.getElementsByClassName('mates').firstChild.innerHTML;
The dot is not a part of the name of the class.
EDIT also notice that the question originally had a typo in firstChild.
Your element variable is not an element (its value is probably undefined). It should work if you use it like this:
var element = document.getElementsByClassName('mates')[0].firstChild;
do {
if(element.innerHTML == 'foo'){
//do something
}
} while (element = element.nextSibling);
The code above fixes:
The class name as pointed out by #Renan
The typo in .firstChild
Also note that getElementsByClassName returns a list of elements, so you have to grab the first one in the list (index 0) to reach your <ul>.
Finally, keep in mind that you'll be looping over all children of the <ul>, including empty text nodes (see a demonstration at http://jsfiddle.net/58ZZF/). This can be avoided if you use firstElementChild and nextElementSibling, but I'm not sure if there are cross browsers issues with those properties (MDN only says it's Firefox 3.5+).
Few mistakes
Class name to getElementsByClassName should not have .
Spelling mistake in firstChild
getElementsByClassName returns an array, not a dom reference
When using nextSibling it could return text nodes also, you need to check the nodeType to make sure the element is a element node(nodeTye = 1), also you can check the tagName == 'LI'
Try
var element = document.getElementsByClassName('mates')[0].firstChild;
do {
if(element.nodeType == 1){
console.log(element.textContent)
}
}while (element = element.nextSibling);
Demo: Fiddle

Determine if element has children with X tag

I am looping through some elements and need to determine if an element has a child(grandchild?) with the li tag, like in the information element below. The li elements will vary in id so I am not referencing them that way. I am currently looping through the li elements and if I check for children it always returns true because there are "a" tag children, I just want to check for 'lil' tag children.
<ul id="navMenu">
<li id="home">Home</li>
<li id="information">Information
<ul>
<li>Credits</li>
<li>Lorem Ipsum</li>
</ul>
</li>
<li id="contact">Contact</li>
</ul>
Here is what I have now...
$('#test').load('../common.html #navMenu', function() {
$.each($("#test #navMenu li"), function(i,v) {
var theElement = $(v);
if ($(theElement).children('li')){
alert('This Element has children');
}
});
});
Thank you once again,
Todd
You could try -
$('#test').load('../common.html #navMenu', function() {
$.each($("#test #navMenu li"), function(i,v) {
var theElement = $(v);
if ($(theElement).find('li').length > 0){
alert('This Element has children');
}
});
});
find will go deeper into the current element than children which only searches one level down.
$(theElement).children('li') returns a jQuery object which always passes an if clause, even when it's empty.
Moreover, you want .find, since .children only returns direct children and not grandchildren.
So:
if ($(theElement).find('li').length > 0) {
or:
if ($(theElement).find('li').length) {
// 0 won't pass an if clause, and all other numbers will, so you can eliminate `> 0`
Given:
> var theElement = $(v);
> if ($(theElement).children('li')) {
> alert('This Element has children');
> }
doesn't $(v) return an jQuery object? So $(theElement) is redundant.
Anyhow, if v is a reference to one of the elements passed to .each, then you can replace all of the above with:
if (v.getElementsByTagName('li').length) {
/* v has li descendants */
]
you could also add the extra li to your query: "#test #navMenu li li"

Displaying nested HTML ul list in columns

I have an autogenerated nested list structure, like so
<ul>
<li>AAA</li>
<li>BBB
<ul>
<li>111
<ul>
<li>XXX</li>
</ul>
</li>
<li>222</li>
</ul>
</li>
<li>CCC</li>
...etc...
</ul>
I want to layout in columns like so:
AAA 111 XXX
BBB 222
CCC
Using JQuery and a few CSS tags, it's then relatively easy to create a navigation style menu. e.g. select BBB from the first column, then this makes its children appear in the second column. Any other second level depth ULs are hidden.
What's leaving me stuck is simply how to style the list in the first place to put the depths into columns. I can add tags to each UL or LI to show the depth. But if I simply use relative positioning and move each column left, then column 1 will leave a vertical gap where each of the entries have been moved across. Absolute positioning works, but doesn't seem too neat. Any better ideas?
Using recursive functions this can be quite straight-forward: http://jsfiddle.net/uvxfm/1/.
If you want interactivity you could save which elements are children of which parent and show the appropriate ones on click.
var $tr = $("#tr");
function text(x) { // returns text without children
return x.clone()
.children()
.remove()
.end()
.text();
}
function add(elem, level) {
elem.children().each(function() { // iterate children
var $this = $(this);
var appendToThis = $tr.find("td").eq(level); // find td to append this level to
var appendedText = text($this) + "<br>"; // text to append
if(appendToThis.length) { // if td exists
appendToThis.append(appendedText);
} else { // if td doesn't exist yet
$tr.append($("<td>").append(appendedText));
}
var children = $this.children();
if(children.length) { // call recursively for children, if any
add(children, level + 1);
}
});
}
add($("ul:eq(0)"), 0); // start the process
References: http://viralpatel.net/blogs/2011/02/jquery-get-text-element-without-child-element.html

Categories

Resources