How to create an array of values from LI inside a UL - javascript

I have a control which allows users to sort the <li> in whatever order they want. when the form submits I want to grab the text inside the <li> for each <li> put into an array, in the order on the form.
<ul id="sortable">
<li class="ui-state-default">
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Protective Services
</li>
<li class="ui-state-default">
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Engineering Services and Public Works
</li>
</ul>
I am grabbing the <li>'s with:
var ar = [];
ar = document.getElementById("sortable").getElementsByTagName("li");
I then go through the array:
for(i = 0; i < ar.length; i++){
alert(ar[i].text()); //ar[i].anything results in console errors.
}
ar[i] displays [object HTMLLIElement] for every <li> available.
if I try to access the .text/.val/id properties inside the items i get a console error. So I'm assuming this has to do with a parsing/conversion issue?
How do I properly create an array that looks like protective services,Engineering Services and Public Works and NOT like [object HTMLLIElement],[object HTMLLIElement]? Or how do I access my text information from the <li> as a [object HTMLLIElement]?

For a pure javascript solution use the innertext property
alert(ar[i].innerText);
Fiddle: http://jsfiddle.net/3fjursaw/

You need to get the jQuery object in order to use text():
alert($(ar[i]).text());
JSFIDDLE: http://jsfiddle.net/rh6ufn23/1/.

You need to use the properties ar[i].innerText or ar[i].textContent on DOM nodes. The method .text() would be used if you had a jQuery object
var lis = document.getElementById("sortable").getElementsByTagName("li");
var data = [];
for(var i=0; i<lis.length; i++){
data.push(lis[i].innerText);
}
var jsonFormated = JSON.stringify(data);
document.getElementById("log").innerHTML = jsonFormated;
<ul id="sortable">
<li class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Protective Services</li>
<li class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Engineering Services and Public Works</li>
</ul>
<div id="log"></div>

the problem is that you work with the HTMLElement, which is of vanilla js, not jQuery. Try .innerHTML instead of .text()

Use :
var ar = [];
var listItems = $("#sortable li");
listItems.each(function(li) {
ar.push($(this).text());
});
Working here: http://jsfiddle.net/csdtesting/0uddfms6/

jQuery solution:
$('li', '#sortable').each(function(){
alert($(this).text());
});
Or to fix your solution in pure JS:
var ar = [];
ar = document.getElementById("sortable").getElementsByTagName("li");
for (i = 0; i < ar.length; i++) {
alert(ar[i].innerText);
}
See fiddle.

Related

Getting value from the custom nav bar

I'm working on the web page where I want to filter products by taking values from the nav bar using JS, like this:
<nav id="shop-nav" class="nav">
<li> value="1">Something</li>
<li> value="2">Something</li>
<li> value="3">Something</li>
<li> value="4">Something</li>
</nav>
My JS code is:
for (let i = 0; i < categories.length; i++) {
const link = document.createElement('li')
link.innerHTML = categories[i].name
link.value = categories[i].id
nav.appendChild(link)
}
I know that this is possible with <select></select> tag, but I want to do it with the custom nav bar.
Thanks
I ran the code you provided and there is an error having to do with categories. Where is categories coming from? Thanks!
Also, I made a small update in the HTML, below.
Blockquote Uncaught ReferenceError: categories is not defined
for (let i = 0; i < categories.length; i++) {
const link = document.createElement('li')
link.innerHTML = categories[i].name
link.value = categories[i].id
nav.appendChild(link)
}
<nav id="shop-nav" class="nav">
<li value="1">Something</li>
<li value="2">Something</li>
<li value="3">Something</li>
<li value="4">Something</li>
</nav>
I may be misunderstanding please correct me if I am. But if you want to get the values from the navbar, you can use queryselector.
let navBarChildren = document.querySelector("nav[id='shop-nav']").children

How can I getElementsByClassName from HTML and push them into a JavaScript Array? How can I then alert this array?

I am trying to gather these HTML objects through getElementsByClassName, and push them into a JavaScript array and then I want to create a JavaScript alert to display these names. I’ve been trying this for hours. Am I doing something wrong?
var names = []
var elm = document.getElementsByClassName('name');
names.push(elm);
var arr = names.join();
alert(arr)
<h2>
List of People:
</h2>
<ul class='people'>
<li class='name'>
Clara
</li>
<li class='name'>
James
</li>
<li class='name'>
Sara
</li>
</ul>
getElementsByClassName does not give you the text inside the elements, but the elements themselves.
Also you won't get them as a proper JavaScript array, but a collection of HTMLElements.
Here's what you can do:
var names = []
var elements = document.getElementsByClassName('name');
for(var i=0; i<elements.length; i++) names.push(elements[i].textContent)
var nameList = names.join()
alert(nameList)
Alternatively you may use Array.from and map:
Array.from(elements).map((elem) => elem.textContent)
Note that I'm using elements[i].textContent to get the text inside each element.
Simply Try with querySelectorAll() .Then apply Nodelist#forEach() to iterate the node list .Finally push into array with element or element attribute which you want
var names = []
var elm = document.querySelectorAll('.name').forEach(function(a){
names.push(a.innerHTML);
});
var arr = names.join();
console.log(arr);
alert(arr)
<h2>
List of People:
</h2>
<ul class='people'>
<li class='name'>
Clara
</li>
<li class='name'>
James
</li>
<li class='name'>
Sara
</li>
</ul>
When we call elements by class name it returns array so you have run loop...
List of People:
<ul class='people'>
<li class='name'>
Clara
</li>
<li class='name'>
James
</li>
<li class='name'>
Sara
</li>
var names = []
var elm = document.getElementsByClassName('name');
for(var i = 0; i < elm.length; i++) {
names.push(elm[i].innerHTML);
}
names.join();
alert(names);
here is jsfiddle running example https://jsfiddle.net/9pt0hf0s/1/

Count of nested ul-li children over multiple levels doesn't always work

I was trying to show the count of all children elements over multiple nested levels beside all li elements which are dynamically generated.
Eg:
Z(8)
A(4)
B
C(2)
D
E
F(2)
G
H
What i am getting now:
Code I used:
Sample HTML:
<li class="li-item">
B R(None)<span class="count-item" data-cnt="2">[2]</span>
<ul class="sub-parent-ul 237">
<li class="li-item">
B R(None)<span class="count-item" data-cnt="3">[3]</span>
<ul class="sub-parent-ul 246">
<li class="li-item">
Bhu Rik(None)<span class="count-item" data-cnt="3">[3]</span>
<ul class="sub-parent-ul 258">
<li class="li-item">Kai Hiwatari(None)<span class="count-item"></span></li>
<li class="li-item">
B R(None)<span class="count-item" data-cnt="2">[2]</span>
<ul class="sub-parent-ul 263">
<li class="li-item">
Bhu Rik(None)<span class="count-item" data-cnt="1">[1]</span>
<ul class="sub-parent-ul 264">
<li class="li-item">B R(None)<span class="count-item"></span></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
JQuery:
$(".sub-parent-ul").each(function() {
// reusabilty
var context = $(this);
// count and populate
var count = context.children().length;
context.prev("a").children().text('['+count+']');
context.prev("a").children().attr('data-cnt',count);
});
$(".sub-parent-ul").each(function() {
var context2 = $(this);
// count and populate
var child_count = context2.children().length;
//check for inner ul
var sub_count = 0;
context2.children('li').each(function () {
var context3 = $(this);
if(context3.children('a').children('span').attr('data-cnt') !== undefined){
sub_count += +context3.children('a').children('span').attr('data-cnt');
}
if(context2.hasClass('G52436')){
console.log(context3.children('a').children('span').attr('data-cnt'));
console.log(context3.children('a').children('span').html());
console.log(context3.children('a').children('span'));
}
});
// final count and populate
var tot_count = child_count+sub_count;
context2.prev("a").children().text('['+tot_count+']');
context2.prev("a").children().attr('data-cnt',tot_count);
});
It works for some levels but not everywhere. I am not sure where i am wrong. What's weird is, I have kept some console logs in the calculation logic which will get the complete count of child count. The js object shows the perfect count which i need, but when i select the attr from the object, it shows different value and that is driving me nuts.
As you can see in the screenshot, the object shows the count as 2 but the value of attribute returns 1. It looks like it is ignoring the data-cnt of immediate child and getting the next child's data-cnt in some cases.
Can someone please identify the issue?
The code doesn't seem to be using recursion, but rather tries to enumerate a set depth (context,context2,context3).
One solution would be to use recursion within the function itself, the other is to use find instead of children to search multiple levels for all the children:
$(".sub-parent-ul").each(function() {
var context = $(this),
children = context.find('li'),
count = children.length,
a = context.prev("a").children();
a.text('['+count+']');
a.data('cnt', count);
});
Not entirely sure it's exactly according to your goal, but the outcome for the example html can be seen in this fiddle

How to convert html tree in to a customized json tree using jquery?

<ul id='parent_of_all'>
<li>
<span class='operator'>&&</span>
<ul>
<li>
<span class='operator'>||</span>
<ul>
<li>
<span class='operator'>&&</span>
<ul>
<li>
<span class='condition'>1 == 1</span>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<span class='condition'>1 != 0</span>
</li>
</ul>
</li>
</ul>
to
{"&&":[{'||':[ {'&&':[ {"lhs": "1", "comparator": "==", "rhs":"1"} ]} ] } , {"lhs": "1", "comparator": "!=", "rhs":"0"}]}
As of now, I know the basics of jQuery, JavaScript. I need to know where to start thinking in order to accomplish the above conversion.
And the html tree could be more complex with more children.
You can do this with each and map
var obj = {}
var span = $('li > span').not('ul li span').text();
$('ul li span').each(function() {
var text = $(this).text().split(' ');
obj[span] = (obj[span]||[]).concat({lhs: text[0], comparator: text[1], rhs: text[2]});
});
console.log(obj)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li>
<span>&&</span>
<ul>
<li>
<span>1 == 1</span>
</li>
</ul>
<ul>
<li>
<span>1 != 0</span>
</li>
</ul>
</li>
You will need a way to select the first level of li, I assumed you have a parent element with an id such as list. I wrote the following code using basic jquery so you can understand it.
var result = {};
var $all_li = $('#list').children('li'); // selecting the first level of li
for(var i in $all_li){ // iterating all_li using for (you may use forEach )
var $current_li = $( $all_li[i] ); // getting operator from first span
var operator = $current_li.children('span').html(); // the text of the operator
var $inner_spans = $current_li.find('>ul >li >span'); // getting list of children spans (from path $list>li>ul>li>span)
var li_spans = []; // an array where we will put the inner span objects
for(var j in $inner_spans){ // iterating the inner spans
var text = $($inner_spans[j]).html().split(" "); // splitting the html
li_spans.push({
lhs: text[0],
comparator: text[1],
rhs: text[2]
}); // adding the splitted html to an object. Note: error if text didn't have 2 white spaces
}
result[operator] = li_spans; // adding the operator key and li_spans value to the result json
}
This code will parse the html and construct the result json, it should work for the html format you provided. Keep in mind that it does not handle errors (such as bad tree format).
simmiar html formats.
Thanks #Alexandru and #Nenad for giving a start. I have been able to complete this on my own.
Below is the function that generates json.
function prepare_json(current_node){
var object = {}
var span = $(current_node).children('span')
if (span.hasClass('condition')){
var text = span.html().split(" ");
object = {lhs: text[0], comparator: text[1], rhs: text[2]}
}
else if(span.hasClass('operator')){
var operator = span.text()
object[operator] = (object[operator] || [])
var children = $(current_node).children('ul').children('li')
for(var i = 0; i < children.length; i++){
var child_pql = prepare_json([children[i]])
object[operator].push(child_pql)
}
}
return object
}
Below is the code that calls that function:
var parent_node = $('#parent_of_all').children('li')
var json = JSON.stringify(prepare_pql_json(parent_node), null, 2)

Storing only the text of a html list item in a javascript array and not the image src as well

In HTML I have an unordered list with items like
<ul id="sortable">
<li class="ui-state-default"><img src="images/john.jpg">John</li>
<li class="ui-state-default"><img src="images/lisa.jpg">Lisa</li>
<li class="ui-state-default"><img src="images/bill.jpg">Bill</li>
<li class="ui-state-default"><img src="images/sara.jpg">Sara</li>
</ul>
I want to store the names of a selected item in an array and the selection is working fine, the problem is that its also storing the img src as well as the name.
This is my code used to populate the array:
var dataArr = [];
$("#sortable li").each(function(idx, elem) {
dataArr[idx] = $(elem).html();
});
If I were then to output dataArr[0] I would get a return string of "< img src="images/ john.jpg ">John" when I obviously just want "John".
Try this: dataArr[idx] = $(elem).text();
.text() will give you only textual children of the node
var dataArr = [];
$("#sortable li").each(function(idx, elem) {
dataArr[idx] = $(elem).text();
});
Use text() instead of html():
dataArr[idx] = $(elem).text();
Or, to be a little cheaper and avoid the cost of wrapping in a jQuery object each iteration:
dataArr[idx] = elem.textContent || elem.innerText;
References:
text().

Categories